﻿
using System;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Collections;
using System.Runtime.InteropServices;

using alib.Debugging;
using alib.Enumerable;
using alib.Collections.ReadOnly;
using alib.Collections;
using alib.String;
using alib.Memory;
using alib.BitArray;

namespace agree
{
#if DEBUG
	static unsafe class _unif_ext
	{
#if false
		public static Unification.UnifierSlot[] ToSdArray(this IEnumerable<IntPtr> ie)
		{
			Unification u;
			IntPtr[] srcarr = ie as IntPtr[];
			if (srcarr != null)
			{
				if (srcarr.Length == 0)
					return Collection<Unification.UnifierSlot>.None;
				u = ((Unification.Scratch*)srcarr[0])->_u;
				Unification.UnifierSlot[] arr = new Unification.UnifierSlot[srcarr.Length];
				for (int i = 0; i < srcarr.Length; i++)
					arr[i] = new Unification.UnifierSlot(srcarr[i]);
				return arr;
			}
			var e = ie.GetEnumerator();
			if (!e.MoveNext())
				return Collection<Unification.UnifierSlot>.None;
			u = ((Unification.Scratch*)e.Current)->_u;
			return _enum_stacker(u, e, 0);
		}

		static Unification.UnifierSlot[] _enum_stacker(Unification u, IEnumerator<IntPtr> e, int c)
		{
			IntPtr ip = e.Current;
			Unification.UnifierSlot[] ret = e.MoveNext() ? _enum_stacker(u, e, c + 1) : new Unification.UnifierSlot[c + 1];
			ret[c] = new Unification.UnifierSlot(ip);
			return ret;
		}
#endif
		public delegate T _func_ps_t<T>(Unification.Slot* ps);

		public static IEnumerable<T> PsSelect<T>(this IEnumerable<IntPtr> ie, _func_ps_t<T> func)
		{
			return new _e_select_ps_t<T>(ie, func);
		}
		class _e_select_ps_t<T> : IEnumerable<T>, IEnumerator<T>
		{
			public _e_select_ps_t(IEnumerable<IntPtr> ie, _func_ps_t<T> func)
			{
				this.e = ie.GetEnumerator();
				this.func = func;
				this.cur = default(T);
			}
			IEnumerator<IntPtr> e;
			T cur;
			_func_ps_t<T> func;
			public T Current { get { return cur; } }
			object IEnumerator.Current { get { return cur; } }
			public bool MoveNext()
			{
				if (!e.MoveNext())
					return false;
				cur = func((Unification.Slot*)e.Current);
				return true;
			}
			public void Dispose() { }
			public void Reset() { }
			public IEnumerator<T> GetEnumerator() { return this; }
			IEnumerator IEnumerable.GetEnumerator() { return this; }
		};
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq} {(f_busy!=0?\"busy\":\"idle\"),nq}")]
	public unsafe sealed partial class Unification : IDisposable
	{
		public static System.IO.TextWriter dtw;
		static bool dbgr_attach = Debugger.IsAttached;
		static readonly Slot*[] rgps_none = new Slot*[0];

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Slot* _ps0, _ps1;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Stack<int> stk;

		SlotPtr[] ToArray(Slot** pps, int c)
		{
			SlotPtr[] arr = new SlotPtr[c];
			for (int i = 0; i < c; i++)
				arr[i] = new SlotPtr(*pps++);
			return arr;
		}

		[DebuggerDisplay("{dcmc.ToString(),nq}")]
		debug_coref_map_class dcmc;
#if DEBUG && UNIF_BREAKPOINTS
		public alib.BitArray.BitArr uix_bp = new alib.BitArray.BitArr(SlotsMax + 1);
		public String bp_clearall() { uix_bp = new alib.BitArray.BitArr(SlotsMax + 1); return ""; }
		public String bp_set(Slot* ps) { uix_bp[ps->uix] = true; return uix_bp.OnesPositions().StringJoin(" "); }
		public String bp_clear(Slot* ps) { uix_bp[ps->uix] = false; return uix_bp.OnesPositions().StringJoin(" "); }
		public String bp_set_chain(Slot* ps)
		{
			foreach (var x in _all_forwarders_and_self((IntPtr)ps))
				uix_bp[((Slot*)x)->uix] = true;
			return uix_bp.OnesPositions().StringJoin(" ");
		}
		public String bp_set(params int[] rguix)
		{
			foreach (int uix in rguix)
				bp_set(ps_base + uix);
			return uix_bp.OnesPositions().StringJoin(" ");
		}
		public String bp_clear(int uix) { return bp_clear(ps_base + uix); }
		public String bp_set_chain(int uix) { return bp_set_chain(ps_base + uix); }
#endif
#if false
		IList<IntPtr> EnumerateSlots(Scratch* ps) { return new ScratchSlotEnum(this, ps); }

		[DebuggerDisplay("{rguix.Length} slots")]
		public sealed class ScratchSlotEnum : IList<IntPtr>
		{
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			readonly Unification u;

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			Scratch** puix;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			Scratch*[] rguix;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			bool f_sorted = false;

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			UnifierSlot[] _rg_sd { get { return this.ToSdArray(); } }

			public UnifierSlot[] ToSdArray()
			{
				if (!f_sorted)
					_sort();
				UnifierSlot[] arr = new UnifierSlot[rguix.Length];
				for (int i = 0; i < rguix.Length; i++)
					arr[i] = new UnifierSlot(rguix[i]);
				return arr;
			}

			public IntPtr[] ToArray()
			{
				if (!f_sorted)
					_sort();
				IntPtr[] arr = new IntPtr[rguix.Length];
				fixed (IntPtr* dst = arr)
				fixed (Scratch** src = rguix)
					Kernel32.CopyMemory(dst, src, rguix.Length * sizeof(Scratch**));
				return arr;
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// 
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			public ScratchSlotEnum(Unification u, Scratch* ps)
			{
				this.u = u;
				int c_act = u.ActiveSlots.Count;

				int cb1 = sizeof(Scratch) * c_act;
				IntPtr p1 = Marshal.AllocHGlobal(cb1);
				Kernel32.CopyMemory((void*)p1, u.ps_base + 1, cb1);

				int cb2 = sizeof(Scratch*) * u.c_corefs;
				IntPtr p2 = Marshal.AllocHGlobal(cb2);
				Kernel32.CopyMemory((void*)p2, u.pps_corefs, cb2);

				Scratch* p = u.ps_base + 1;
				u._rfi = null;
				for (int i = 0; i < c_act; i++, p++)
				{
					if (p->gen < u.gen)
					{
						//p->_set_forward(0);
						p->forward = 0;
#if P1_COUNT
						p->c_cnt = 0;
#endif
					}
				}

				rgbx = new byte[c_act + 1];
				{
					Scratch** _rg = stackalloc Scratch*[c_act];
					puix = _rg;

					_count_below(ps);
					int c = (int)(puix - _rg);

					rguix = new Scratch*[c];
					fixed (Scratch** prg = rguix)
						Kernel32.CopyMemory(prg, _rg, c * sizeof(Scratch*));
				}

				Kernel32.CopyMemory(u.pps_corefs, (void*)p2, cb2);
				Marshal.FreeHGlobal(p2);
				Kernel32.CopyMemory(u.ps_base + 1, (void*)p1, cb1);
				Marshal.FreeHGlobal(p1);
				u._rfi = null;
			}

			byte[] rgbx;

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// 
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void _count_below(Scratch* ps)
			{
				Scratch* nps;
				int ix, fwd;
				ushort* pfix = *(ushort**)((long)u.rgpfix + ((int)ps->f << 3));
				pinfo* pi = u.pbx + ps->tfsix;
				do
				{
					if ((ix = pi->_fetch_ix_only(*pfix, ps->m_src)) == 0)
						continue;

					int uix = ix + pi->uix;
					rgbx[uix] += 0x00000001;
					if (rgbx[uix] > 1)
						continue;

					if (*pfix == u.ifeat_restrict)
					{
						continue;
					}

					Scratch* ps_in = (Scratch*)((long)u.ps_base + (uix << SHL_PS));
					if (ps_in->gen == u.gen + g_ind)
					{
						continue;
					}

					if (ps_in->gen < u.gen)
					{
						ps_in->tfsix = (short)pi->tfsix;
						Edge ne = pi->tfs.entries[ix - 1].e;
						if (ne.Mark < 0)
						{
							Scratch** pps;
							if ((nps = *(pps = pi->coref_designations - ne.Mark)) != null)
							{
								ps_in->_set_forward((int)((long)u.ps_base - (long)nps));
								goto deref;
							}
							*pps = ps_in;
						}
						ps_in->_set_forward(0);	/// (debugging aid)
#if P1_COUNT
						ps_in->c_cnt = 0;
#endif
						ps_in->e_ul = *(ulong*)&ne & 0xFFFFFFFF7FFFFFFF;
					}
					nps = ps_in;

				deref:
					while ((fwd = nps->forward) < 0)
						nps = (Scratch*)((long)u.ps_base - fwd);
					//rgwp[nps->_thisix] += 0x00010000;

					if ((nps->f & Edge.Flag.EtmNonBareType) != 0)
						_count_below(nps);

					*puix++ = ps_in;
				}
				while (*++pfix != 0xFFFF);
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// 
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void _sort()
			{
				if (!f_sorted)
				{
					fixed (Scratch** prg = rguix)
						alib.Array._array_ext.qsort((IntPtr*)prg, 0, rguix.Length - 1, cc.CmpInst);
					f_sorted = true;
				}
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// 
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			public Scratch* this[int index]
			{
				get { if (!f_sorted) _sort(); return rguix[index]; }
				set { throw new InvalidOperationException(); }
			}
			IntPtr IList<IntPtr>.this[int index]
			{
				get { if (!f_sorted) _sort(); return (IntPtr)rguix[index]; }
				set { throw new InvalidOperationException(); }
			}

			public int Count { get { return rguix.Length; } }
			public bool IsReadOnly { get { return true; } }
			public void CopyTo(IntPtr[] array, int arrayIndex)
			{
				if (!f_sorted)
					_sort();
				fixed (IntPtr* dst = array)
				fixed (Scratch** src = rguix)
					Kernel32.CopyMemory(dst + (arrayIndex * sizeof(Scratch**)), src, (rguix.Length - arrayIndex) * sizeof(Scratch**));
				//while (arrayIndex > 0)
				//    array[arrayIndex--] = (IntPtr)rguix[arrayIndex];
			}

			public int IndexOf(IntPtr item) { throw not.impl; }
			public bool Contains(IntPtr item) { throw not.impl; }
			public void Insert(int index, IntPtr item) { throw new InvalidOperationException(); }
			public void RemoveAt(int index) { throw new InvalidOperationException(); }
			public void Add(IntPtr item) { throw new InvalidOperationException(); }
			public void Clear() { throw new InvalidOperationException(); }
			public bool Remove(IntPtr item) { throw new InvalidOperationException(); }

			IntPtr _get(int ix) { return (IntPtr)rguix[ix]; }
			public IEnumerator<IntPtr> GetEnumerator()
			{
				if (!f_sorted)
					_sort();
				int c = Count;
				for (int i = 0; i < c; i++)
					yield return _get(i);
			}
			System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
		};
#endif

		public String CsvSlots()
		{
			System.Text.StringBuilder sb = new System.Text.StringBuilder();

			int c = ActiveSlots.Count;
			Slot* ps = ps_base;
			for (int i = 0; i <= c; i++, ps++)
			{
				String s_forward = "", s_type = "", s_status = "", s_feat = "", s_inmark = "", s_m_src = "";

				if (i == 0)
				{
					s_status = "";
				}
				else
				{
					pinfo* pi = ps->_pi;

					if (i == pi->uix0)
					{
						s_feat = "(root slot " + (pi->tfsix == 1 ? "M" : "D") + ")";
						s_m_src = "1";
					}
					else
					{
						arr_tfs_entry ate = pi->entries[i - pi->uix0 - 1];

						s_feat = ftm[ate.i_feat].feature.ToUpper();
						s_inmark = ate.mark.ToString();
						s_m_src = ate.e_Mark.ToString();
					}

					if (ps->gen < gen)
					{
						s_status = "old";
						s_m_src = "";
					}
					else
					{
						s_status = "";

						if (ps->forward == 0)
						{
							s_type = ftm.tu.GetEdgeType(ps->f).Name;
							s_forward = "0";
						}
						else
						{
							s_forward = (-ps->forward >> SHL_PS).ToString();
							s_m_src = "";
						}
					}
				}

				sb.AppendFormat("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\r\n",
					i,
					ps->tfsix,
					s_inmark,
					s_feat,
					s_status,
					s_forward,
					s_type,
					s_m_src);
			}
			return sb.ToString();
		}

		class cc : IComparer<IntPtr>, IEqualityComparer<IntPtr>
		{
			public static IEqualityComparer<IntPtr> EqInst = new cc();
			public static IComparer<IntPtr> CmpInst = (cc)EqInst;
			public int Compare(IntPtr x, IntPtr y)
			{
				return (int)((long)x - (long)y);
			}

			public bool Equals(IntPtr x, IntPtr y)
			{
				return (void*)x == (void*)y;
			}

			public int GetHashCode(IntPtr obj)
			{
				return (int)obj;
			}
		};

		struct saved_state
		{
			Unification u;
			Slot[] scr_sav;
			Slot*[] coref_sav;
			int c_participants;
			uint gen;
			//int count_p3;
			int next_mark;
			int next_coref_mark;
			int c_init_nodes;

			public saved_state(Unification u)
			{
				this.u = u;
				this.gen = u.gen;
				this.c_participants = u.c_participants;

				//this.count_p3 = u.count_p3;
				this.next_mark = u.next_mark;
				this.next_coref_mark = u.next_coref_mark;
				this.c_init_nodes = u.c_init_nodes;

				int c_act = u.ActiveSlots.Count + 1;
				if (u.count_p3 > c_act)
					c_act = (int)u.count_p3;

				this.scr_sav = new Slot[c_act];
				fixed (Slot* _ss = scr_sav)
					Kernel32.CopyMemory(_ss, u.ps_base, scr_sav.Length * sizeof(Slot));

				this.coref_sav = new Slot*[u.c_corefs];
				fixed (Slot** _pp = coref_sav)
					Kernel32.CopyMemory(_pp, u.pps_corefs, u.c_corefs * sizeof(Slot*));
			}

			public void Restore()
			{
				if (u == null || scr_sav == null || coref_sav == null)
					return;
				if (this.gen != u.gen || this.c_participants != u.c_participants || coref_sav.Length != u.c_corefs)
					throw new Exception();

				fixed (Slot* _ss = scr_sav)
					Kernel32.CopyMemory(u.ps_base, _ss, scr_sav.Length * sizeof(Slot));
				u._rfi = null;

				fixed (Slot** _pp = coref_sav)
					Kernel32.CopyMemory(u.pps_corefs, _pp, coref_sav.Length * sizeof(Slot*));

				u.next_mark = this.next_mark;
				u.next_coref_mark = this.next_coref_mark;
				u.c_init_nodes = this.c_init_nodes;
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Slot* ps_last
		{
			get
			{
#if DEBUG
				if (c_participants == 0 || pbx == null)
					return ps_base;
#endif
				return ps_base + (pbx + c_participants + 1)->uix0;
			}
		}
		public pinfo* _find_pi_for_old(Slot* ps)
		{
			if (ps == null)
				return null;
			if (ps->gen >= gen)
				return pbx + ps->tfsix;
			int uix = ps->uix;
			pinfo* pi = pbx + 1;
			for (int i = 0; i < c_participants; i++, pi++)
				if (uix < pi[1].uix0)
					return pi;
			return null;
		}
		public pinfo* _find_pi_for_old(int uix)
		{
			if (uix <= 0)
				throw new Exception();
			Slot* ps;
			if ((ps = ps_base + uix)->gen >= gen)
				return pbx + ps->tfsix;
			pinfo* pi;
			for (int i = 1; i <= c_participants; i++)
				if (((pi = pbx + i) + 1)->uix0 >= uix)
					return pi;
			return null;
		}

		void _debug_new()
		{
			if (dbgr_attach)
			{
#if FEATURE_PATH
				this.stk = new Stack<int>();
#endif
				dcmc = new debug_coref_map_class(this);
			}

			this.ActiveSlots = new _active_slot_list(this);
			//this.asd = new _active_scratch_debug(this);
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public static int c_slots_max = 0;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public static int c_part_max = 0;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public static int c_corefs_max = 0;
		void _debug_tfs_init(pinfo* pi)
		{
			if (ActiveSlots.Count > c_slots_max)
			{
				c_slots_max = ActiveSlots.Count;
				//Console.Write("[slots:{0}] ",c_slots_max);
			}
			if (c_participants > c_part_max)
			{
				c_part_max = c_participants;
				//Console.Write("[tfs-args:{0}] ", c_part_max);
			}
			if (c_corefs > c_corefs_max)
			{
				c_corefs_max = c_corefs;
				//Console.Write("[corefs:{0}] ", c_corefs_max);
			}

#if UNIFIER_DEBUGGING
			Slot* ps = ps_base + pi->uix0;
			short tfsix = (short)pi->tfsix;
			for (int i = 0; i < pi->SlotCount; i++, ps++)
				ps->tfsix = tfsix;
#endif
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		[DebuggerStepThrough]
		void _check_args(Edge.Flag f, Slot* ps0, Slot* ps1)
		{
			Debug.Assert(ps0->tfsix > 0 && ps1->tfsix > 0);
			Debug.Assert(ps0->m_src != 0 && ps1->m_src != 0);
			Debug.Assert(ps0->m_src != ps1->m_src || ps0->tfsix != ps1->tfsix);
			//Debug.Assert(*rgpfix[(int)(f & Edge.Flag.MultiIdMask)] > 0);
			//if (dbgr_attach)
			//{
			//    _ps0 = bases[tfsix0] + (m0 < 0 ? m0 : m0 == TopmostMark ? 0 : GetMix(tfsix0, m0));
			//    _ps1 = bases[tfsix1] + (m1 < 0 ? m1 : m1 == TopmostMark ? 0 : GetMix(tfsix1, m1));
			//    Debug.Assert(_ps0 != _ps1);
			//}
			if (stk != null)
				stk.Push(0);
		}
		[DebuggerStepThrough]
		void _change_stack_top(ushort i_feat)
		{
			if (stk != null)
			{
				stk.Pop(); stk.Push(i_feat);
			}
		}

		[DebuggerStepThrough]
		void _debug_nps_single(Slot* ps, Slot* nps)
		{
			if (dtw != null)
			{
			}
		}


		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String CurrentPath
		{
			get
			{
				return stk == null ? "" : stk.Reverse()
											.Select(fix => ftm[fix].feature)
											.StringJoin(".");
			}
		}

#if REVERSE_INDEX
		public void get_source_coref_counts(int tfsix, int m, out int c_pnd, out int c_loc)
		{
			get_source_coref_counts(pbx + tfsix, m, out c_pnd, out c_loc);
		}
		public void get_source_coref_counts(pinfo* pi, int m, out int c_pnd, out int c_loc)
		{
			Slot* ps_tbase = ps_base + pi->uix0;
			c_pnd = 0;
			c_loc = 0;
			foreach (int ix in pi->tfs.GetOutMarkSlots(m))
			{
				c_loc++;
				if (ps_tbase[ix].gen < gen)
					c_pnd++;
			}
			if (m > 0 && c_loc > 1)
				throw new Exception();
		}
#endif
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		ReadOnlyDictionary<IntPtr, List<IntPtr>> _rfi;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public ReadOnlyDictionary<IntPtr, List<IntPtr>> _reverse_forwarding_index
		{
			get
			{
				var _tmp = _rfi;
				if (_tmp == null)
					_rfi = _tmp = _rebuild_rfi();
				return _tmp;
			}
		}

		ReadOnlyDictionary<IntPtr, List<IntPtr>> _rebuild_rfi()
		{
			int c = Math.Min(Math.Max(ActiveSlots.Count, count_p3), SlotsMax);
			if (c == 0)
				return ReadOnlyDictionary<IntPtr, List<IntPtr>>.Empty;

			GCHandle* _rgh = stackalloc GCHandle[c + 1];
			GCHandle* rgh = _rgh;
			Slot* ps = ps_base + 1;
			int fwd, c_ent = 0;

			for (int i = 0; i < c; i++, ps++)
				if (ps->gen >= gen && (fwd = ps->forward) < 0)
				{
					List<IntPtr> l;
					int ix = (-fwd >> SHL_PS);
					if (ix >= c + 1)
						throw new Exception();
					GCHandle* ph = rgh + ix;
					if (ph->IsAllocated)
						l = (List<IntPtr>)ph->Target;
					else
					{
						l = new List<IntPtr>();
						*ph = GCHandle.Alloc(l, GCHandleType.Normal);
						c_ent++;
					}
					l.Add((IntPtr)ps);
				}

			return new ReadOnlyDictionary<IntPtr, List<IntPtr>>(
				c_ent,
				new IntPtrEnumerator(rgh, c_ent, ps_base),
				ip =>
				{
					GCHandle* ph = rgh + ((int)((Slot*)ip - ps_base));
					var lx = (List<IntPtr>)ph->Target;
					ph->Free();
					lx.Sort(cc.CmpInst);
					return lx;
				},
				cc.EqInst);
		}

		class IntPtrEnumerator : IEnumerator<IntPtr>
		{
			public IntPtrEnumerator(GCHandle* rgh, int c_ent, Slot* ps_start)
			{
				this.prgh = rgh;
				this.c_ent = c_ent;
				this.ps = ps_start;
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			GCHandle* prgh;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			int c_ent;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			Slot* ps;

			public bool MoveNext()
			{
				if (c_ent == 0)
					return false;
				c_ent--;
				do
				{
					prgh++;
					ps++;
				}
				while (!prgh->IsAllocated);
				return true;
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public IntPtr Current { get { return (IntPtr)ps; } }
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			object IEnumerator.Current { get { return (IntPtr)ps; } }

			public void Reset() { }
			public void Dispose() { }
		};
#if false
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		ReadOnlyDictionary<IntPtr, List<IntPtr>> _rpi;

		public ReadOnlyDictionary<IntPtr, List<IntPtr>> _reverse_path_index(Scratch* ps_top)
		{
			var _tmp = _rfi;
			if (_tmp == null)
			{
				_rpi = _tmp = new _path_scan(this)._rebuild_rpi(ps_top);
			}
			return _tmp;
		}

		class _path_scan
		{
			public _path_scan(Unification u)
			{
				this.u = u;
				this.ugen = u.ugen;
				this.ps_base = u.ps_base;

			}
			GCHandle* rgh;
			Unification u;
			uint ugen;
			Scratch* ps_base;

			public ReadOnlyDictionary<IntPtr, List<IntPtr>> _rebuild_rpi(Scratch* ps)
			{
				int c = Math.Min(Math.Max(u.ActiveSlots.Count, u.count_p3), SlotsMax);
				if (c == 0)
					return ReadOnlyDictionary<IntPtr, List<IntPtr>>.Empty;

				GCHandle* _rgh = stackalloc GCHandle[c + 1];

				pinfo* pi = ps->_pi;

				_scan_rpi(pi, *(ushort**)((long)u.rgpfix + ((int)ps->f << 3)), pi->tfs.TopEdge.Mark);

#if false
				for (int i = 0; i < c; i++, ps++)
					if (ps->gen >= gen && (fwd = ps->forward) < 0)
					{
						List<IntPtr> l;
						int ix = (-fwd >> SHL_PS);
						if (ix >= c + 1)
							throw new Exception();
						GCHandle* ph = rgh + ix;
						if (ph->IsAllocated)
							l = (List<IntPtr>)ph->Target;
						else
						{
							l = new List<IntPtr>();
							*ph = GCHandle.Alloc(l, GCHandleType.Normal);
							c_ent++;
						}
						l.Add((IntPtr)ps);
					}
#endif
				//return new ReadOnlyDictionary<IntPtr, List<IntPtr>>(
				//    c_ent,
				//    new IntPtrEnumerator(rgh, c_ent, ps_base),
				//    ip =>
				//    {
				//        GCHandle* ph = rgh + ((int)((Scratch*)ip - ps_base));
				//        var lx = (List<IntPtr>)ph->Target;
				//        ph->Free();
				//        lx.Sort(cc.CmpInst);
				//        return lx;
				//    },
				//    cc.EqInst);

				return null;
			}

			void _scan_rpi(pinfo* pi, ushort* pfix, int m_src)
			{
				Scratch* nps, ps_act;
				do
				{
					if (*pfix == u.ifeat_restrict)
						continue;

					int ix;
					if ((ix = pi->_fetch_ix_only(*pfix, m_src)) == 0)
						continue;

					Edge ne;
					int fwd;
					if ((ps_act = (Scratch*)((long)ps_base + ((ix + pi->uix) << SHL_PS)))->gen < u.gen)
					{
						if ((ne = ((arr_tfs_entry*)((long)pi->entries + ((ix - 1) << 4)))->e).FlagsId < 0)
						{
							Scratch** pps;
							if ((nps = *(pps = pi->coref_designations - ne.Mark)) != null)
							{
#if DEBUG
								ps_act->_set_forward((int)((long)ps_base - (long)nps));
#else
								ps_act->forward = (int)((long)ps_base - (long)nps);
#endif
								goto fwd;
							}
							*pps = ps_act;
						}
#if DEBUG
						ps_act->_set_forward(0);
#else
						ps_act->forward = 0;
#endif
						//c_init_nodes++;
						ps_act->tfsix = (short)pi->tfsix;
						ps_act->e_ul = *(ulong*)&ne & 0xFFFFFFFF7FFFFFFF;
						nps = ps_act;
						goto no_fwd;
					}
					nps = ps_act;
				fwd:
					while ((fwd = nps->forward) < 0)
						nps = (Scratch*)((long)ps_base - fwd);

				no_fwd:
					if (nps->gen < ugen)
					{
						nps->gen = ugen;
						if ((nps->f & Edge.Flag.EtmNonBareType) != 0)
							_scan_rpi(u.pbx + nps->tfsix, *(ushort**)((long)u.rgpfix + ((int)nps->f << 3)), nps->m_src);
					}
					ps_act->gen = ugen;
				}
				while (*++pfix != 0xFFFF);
			}
		};
#endif

		[DebuggerDisplay("{ToString(),nq}")]
		public class ForwardChainSet
		{
			public ForwardChainSet(Unification u, IEnumerable<IntPtr> seq)
			{
				_root = seq.Select(x => new SlotPtr(x)).ToArray();

				s = u._format_forward_chain(seq);
			}

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			public readonly SlotPtr[] _root;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			readonly String s;

			public override string ToString() { return s; }
		};

		public ForwardChainSet[] active_forwarders(Slot* ps)
		{
			return fwd_chains((IntPtr)ps)
						.Where(cip => cip.Count > 1)
						.Select(x => new ForwardChainSet(this, x))
						.ToArray();
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public IntPtr _ps_base { get { return (IntPtr)ps_base; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		const int _sizeof_scratch = (1 << SHL_PS);

		//[DebuggerTypeProxy(typeof(_dbg_proxy))]
		public class _active_slot_list : IList<IntPtr>
		{
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			Unification u;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			Slot* ps_base;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			IntPtr _ps_base;

			public _active_slot_list(Unification u)
			{
				this.u = u;
				this._ps_base = (IntPtr)(this.ps_base = u.ps_base);
			}

			public IntPtr this[int index]
			{
				get { return (IntPtr)(ps_base + (index - 1)); }
				set { throw new InvalidOperationException(); }
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public int Count { get { return (u.pbx + u.c_participants + 1)->uix0 - 1; } }

			public IEnumerator<IntPtr> GetEnumerator()
			{
				IntPtr ps = _ps_base + _sizeof_scratch;
				int c = Count;
				for (int i = 0; i < c; i++)
				{
					yield return ps;
					ps = ps + _sizeof_scratch;
				}
			}

			public int IndexOf(IntPtr item)
			{
				int ix = (int)(((Slot*)item - 1) - ps_base);
				return ix < 0 || ix >= Count ? -1 : ix;
			}
			public bool Contains(IntPtr _item)
			{
				Slot* item = (Slot*)_item;
				return ps_base < item && item - 1 < ps_base + Count;
			}

			public void CopyTo(IntPtr[] array, int arrayIndex)
			{
				Slot* ps = ps_base + 1;
				int c = Count;
				for (int i = 0; i < c; i++, ps++)
					array[arrayIndex++] = (IntPtr)ps;
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public bool IsReadOnly { get { return true; } }
			public void Insert(int index, IntPtr item) { throw new InvalidOperationException(); }
			public void RemoveAt(int index) { throw new InvalidOperationException(); }
			public bool Remove(IntPtr item) { throw new InvalidOperationException(); }
			public void Add(IntPtr item) { throw new InvalidOperationException(); }
			public void Clear() { throw new InvalidOperationException(); }
			IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
		};

		//[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]	//[1...{active_slots}]  
		//[DebuggerDisplay("TFSes:{c_participants}  tot:{ActiveSlots.Count}  old:{_count_old(0)}  mst:{_count_mst(0)}  fwd:{_count_fwd(0)}  nmf:{_count_nmf(0)}  ind:{_count_gen(0,3)}  cnt:{_count_cnt(0)}")]

		[DebuggerDisplay("TFSes:{c_participants}", Name = "input TFS args")]
		public u_pinfo[] zz00_dbg_participants
		{
			get
			{
				u_pinfo[] rg = new u_pinfo[c_participants];
				for (int i = 1; i <= c_participants; i++)
					rg[i - 1] = new u_pinfo(this, pbx + i);
				return rg;
			}
		}

		//[DebuggerDisplay("All slots")]
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public _active_slot_list ActiveSlots;

		//[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//[DebuggerDisplay("{ActiveSlots.Count}")]
		[DebuggerDisplay("total slots:{ActiveSlots.Count}", Name = "all slots")]
		public SlotPtr[] zz00_dbg_all
		{
			get
			{
				int c = ActiveSlots.Count;
				Unification.SlotPtr[] arr = new Unification.SlotPtr[c];
				Slot* ps = ps_base + 1;
				for (int i = 0; i < c; i++, ps++)
					arr[i] = new SlotPtr(ps);
				return arr;
			}
		}

		//[DebuggerDisplay("click to expand")]
		public SlotPtr[] zz01_dbg_old
		{
			get
			{
				int c = ActiveSlots.Count;
				Slot** _pps = stackalloc Slot*[c];
				Slot** pps = _pps;
				Slot* ps = ps_base + 1;
				for (int i = 0; i < c; i++, ps++)
					if (ps->gen < gen)
						*pps++ = ps;
				return ToArray(_pps, (int)(pps - _pps));
			}
		}

		//[DebuggerDisplay("click to expand")]
		public SlotPtr[] zz02_dbg_cur
		{
			get
			{
				int c = ActiveSlots.Count;
				Slot** _pps = stackalloc Slot*[c];
				Slot** pps = _pps;
				Slot* ps = ps_base + 1;
				for (int i = 0; i < c; i++, ps++)
					if (ps->gen >= gen)
						*pps++ = ps;
				return ToArray(_pps, (int)(pps - _pps));
			}
		}

		public SlotPtr[] zz03_dbg_cur_except_g0
		{
			get
			{
				int c = ActiveSlots.Count;
				Slot** _pps = stackalloc Slot*[c];
				Slot** pps = _pps;
				Slot* ps = ps_base + 1;
				for (int i = 0; i < c; i++, ps++)
					if (ps->gen > gen)
						*pps++ = ps;
				return ToArray(_pps, (int)(pps - _pps));
			}
		}

		public SlotPtr[] _dbg_gen(int g)
		{
			int c = ActiveSlots.Count;
			Slot** _pps = stackalloc Slot*[c];
			Slot** pps = _pps;
			Slot* ps = ps_base + 1;
			uint target_gen = gen + (uint)g;
			for (int i = 0; i < c; i++, ps++)
				if (ps->gen == target_gen)
					*pps++ = ps;
			return ToArray(_pps, (int)(pps - _pps));
		}

		//[DebuggerDisplay("click to expand")]
		public SlotPtr[] zz04_dbg_g0 { get { return _dbg_gen(0); } }
		//[DebuggerDisplay("click to expand")]
		public SlotPtr[] zz05_dbg_g1 { get { return _dbg_gen(1); } }
		//[DebuggerDisplay("click to expand")]
		public SlotPtr[] zz06_dbg_g2 { get { return _dbg_gen(2); } }
		//[DebuggerDisplay("click to expand")]
		public SlotPtr[] zz07_dbg_g3 { get { return _dbg_gen(3); } }
		//[DebuggerDisplay("click to expand")]
		public SlotPtr[] zz08_dbg_g4 { get { return _dbg_gen(4); } }
		//[DebuggerDisplay("click to expand")]
		public SlotPtr[] zz09_dbg_g5 { get { return _dbg_gen(5); } }
		public SlotPtr[] zz10_dbg_g6 { get { return _dbg_gen(6); } }
		public SlotPtr[] zz11_dbg_g7 { get { return _dbg_gen(7); } }

		//[DebuggerDisplay("click to expand")]
		public SlotPtr[] zz12_dbg_mst
		{
			get
			{
				int c = ActiveSlots.Count;
				Slot** _pps = stackalloc Slot*[c];
				Slot** pps = _pps;
				Slot* ps = ps_base + 1;
				for (int i = 0; i < c; i++, ps++)
					if (ps->gen >= gen && ps->forward == 0)
						*pps++ = ps;
				return ToArray(_pps, (int)(pps - _pps));
			}
		}

		//[DebuggerDisplay("click to expand")]
		public SlotPtr[] zz13_dbg_fwd
		{
			get
			{
				int c = ActiveSlots.Count;
				Slot** _pps = stackalloc Slot*[c];
				Slot** pps = _pps;
				Slot* ps = ps_base + 1;
				for (int i = 0; i < c; i++, ps++)
					if (ps->gen >= gen && ps->forward < 0)
						*pps++ = ps;
				return ToArray(_pps, (int)(pps - _pps));
			}
		}

#if false
		//[DebuggerDisplay("click to expand")]
		public UnifierSlot[] zz00_dbg_target_mark_neg
		{
			get
			{
				int c = ActiveSlots.Count;
				Scratch** _pps = stackalloc Scratch*[c];
				Scratch** pps = _pps;
				Scratch* ps = ps_base + 1;
				uint target_gen = gen + 4;
				for (int i = 0; i < c; i++, ps++)
					if (ps->gen >= target_gen)
					{
						Scratch* ps_fwd = ps;
						int fwd;
						while ((fwd = ps_fwd->forward) < 0)
							ps_fwd = (Scratch*)((long)ps_fwd - fwd);
						if (ps_fwd->m_src < 0)
							*pps++ = ps;
					}
				return ToArray(_pps, (int)(pps - _pps));
			}
		}
#else
		//[DebuggerDisplay("click to expand")]
		public SlotPtr[] zz14_dbg_target_mark_neg
		{
			get
			{
				int c = ActiveSlots.Count;
				Slot** _pps = stackalloc Slot*[c];
				Slot** pps = _pps;
				Slot* ps = ps_base + 1;
				uint target_gen = gen + 4;
				for (int i = 0; i < c; i++, ps++)
					if (ps->gen >= target_gen && ps->forward == 0 && ps->m_src < 0)
						*pps++ = ps;
				return ToArray(_pps, (int)(pps - _pps));
			}
		}
#endif

		//[DebuggerDisplay("click to expand")]
		public SlotPtr[] zz15_dbg_except_target_mark_neg
		{
			get
			{
				int c = ActiveSlots.Count;
				Slot** _pps = stackalloc Slot*[c];
				Slot** pps = _pps;
				Slot* ps = ps_base + 1;
				uint target_gen = gen + 4;
				for (int i = 0; i < c; i++, ps++)
					if (ps->gen < target_gen || ps->forward < 0 || ps->m_src >= 0)
						*pps++ = ps;
				return ToArray(_pps, (int)(pps - _pps));
			}
		}


		public SlotPtr[] zz16_dbg_src_mark_neg
		{
			get
			{
				int c = ActiveSlots.Count;
				Slot** _pps = stackalloc Slot*[c];
				Slot** pps = _pps;
				Slot* ps = ps_base + 1;
				pinfo* pi = pbx + 1;
				int i = 1;
				while (true)
				{
					int ix = i - pi->uix0;
					int m = ix == 0 ? pi->tfs._top_edge.Mark : pi->entries[ix - 1].e_Mark;
					if (m < 0)
						*pps++ = ps;
					ps++;
					i++;
					if (i > c)
						break;
					if (i == (pi + 1)->uix0)
						pi++;
				}
				return ToArray(_pps, (int)(pps - _pps));
			}
		}

#if P1_COUNT
		public UnifierSlot[] zz17_dbg_nonzero_cnt
		{
			get
			{
				int c = ActiveSlots.Count;
				Scratch** _pps = stackalloc Scratch*[c];
				Scratch** pps = _pps;
				Scratch* ps = ps_base + 1;
				for (int i = 0; i < c; i++, ps++)
					if (ps->gen >= gen && ps->forward == 0 && ps->c_cnt > 0)
						*pps++ = ps;
				return ToArray(_pps, (int)(pps - _pps));
			}
		}

		public UnifierSlot[] zz18_dbg_lt_type_cnt
		{
			get
			{
				int c = ActiveSlots.Count;
				Scratch** _pps = stackalloc Scratch*[c];
				Scratch** pps = _pps;
				Scratch* ps = ps_base + 1;
				for (int i = 0; i < c; i++, ps++)
					if (ps->gen >= gen && ps->forward == 0 &&
						ps->c_cnt > 0 &&
						((ps->f & Edge.Flag.EtmNonBareType) == 0 ||
						ps->c_cnt != (*(ushort**)((long)rgpfix + ((int)ps->f << 3)))[-1]))
					{
						*pps++ = ps;
					}
				return ToArray(_pps, (int)(pps - _pps));
			}
		}

		public UnifierSlot[] zz19_dbg_counted_via_parent
		{
			get
			{
				int c = ActiveSlots.Count;
				bool* _pb = stackalloc bool[c + 1];
				Scratch* ps = ps_base + 1;
				for (int uix = 1; uix <= c; uix++, ps++)
					if (ps->gen >= gen && ps->forward == 0 && ps->c_cnt > 0)
					{
						if ((ps->f & Edge.Flag.EtmNonBareType) == 0)
							throw new Exception();

						pinfo* pi = pbx + ps->tfsix;
						int ix = uix - pi->uix, nix;
						int m_src = ix == 0 ? pi->tfs.TopEdge.Mark : pi->entries[ix - 1].e_Mark;
						ushort* pfix = *(ushort**)((long)rgpfix + ((int)ps->f << 3));
						do
							if ((nix = pi->_fetch_ix_only(*pfix, m_src)) != 0)
								_pb[pi->uix + nix] = true;
						while (*++pfix != 0xFFFF);
					}

				Scratch** _pps = stackalloc Scratch*[c];
				Scratch** pps = _pps;
				bool* pb = _pb + 1;
				ps = ps_base + 1;
				for (int i = 0; i < c; i++, ps++, pb++)
					if (*pb)
						*pps++ = ps;

				return ToArray(_pps, (int)(pps - _pps));
			}
		}

		public UnifierSlot[] zz20_dbg_parent_with_unavail
		{
			get
			{
				int c = ActiveSlots.Count;
				Scratch** _pps = stackalloc Scratch*[c];
				Scratch** pps = _pps;
				Scratch* ps = ps_base + 1;
				for (int uix = 1; uix <= c; uix++, ps++)
					if (ps->gen >= gen && ps->forward == 0 && ps->c_cnt > 0)
					{
						if ((ps->f & Edge.Flag.EtmNonBareType) == 0)
							throw new Exception();

						pinfo* pi = pbx + ps->tfsix;
						int ix = uix - pi->uix, nix;
						int m_src = ix == 0 ? pi->tfs.TopEdge.Mark : pi->entries[ix - 1].e_Mark;
						ushort* pfix = *(ushort**)((long)rgpfix + ((int)ps->f << 3));
						do
							if ((nix = pi->_fetch_ix_only(*pfix, m_src)) == 0)
								*pps++ = ps;
						while (*++pfix != 0xFFFF);
					}
				return ToArray(_pps, (int)(pps - _pps));
			}
		}
#endif

		public SlotPtr[] zz22_dbg_counted_via_parent2
		{
			get
			{
				int c = ActiveSlots.Count;
				bool* _pb = stackalloc bool[c + 1];
				Slot* ps = ps_base + 1;
				for (int uix = 1; uix <= c; uix++, ps++)
					if (ps->gen >= gen && ps->gen != gen + 3 && ps->forward == 0 && (ps->f & Edge.Flag.EtmNonBareType) != 0)
					{
						pinfo* pi = pbx + ps->tfsix;
						int ix = uix - pi->uix0, nix;
						int m_src = ix == 0 ? pi->tfs._top_edge.Mark : pi->entries[ix - 1].e_Mark;
						ushort* pfix = *(ushort**)((long)rgpfix + ((int)ps->f << 3));
						do
							if ((nix = pi->_fetch_ix_only(*pfix, m_src)) != 0)
								_pb[pi->uix0 + nix] = true;
						while (*++pfix != 0xFFFF);
					}

				Slot** _pps = stackalloc Slot*[c];
				Slot** pps = _pps;
				bool* pb = _pb + 1;
				ps = ps_base + 1;
				for (int i = 0; i < c; i++, ps++, pb++)
					if (*pb)
						*pps++ = ps;

				return ToArray(_pps, (int)(pps - _pps));
			}
		}

		public String zz22_paths_via_parent_x3
		{
			get
			{
				var pw = new _path_walker_x3(this, ps_base + 1);
				return pw.Count.ToString() + Environment.NewLine +
						pw.Sort().StringJoin(Environment.NewLine);
			}
		}

		class _path_walker_x3i : HashSet<String>
		{
			public _path_walker_x3i(Unification u, Slot* ps)
			{
				this.u = u;
				this.gen = u.gen;
				this.path = new Stack<String>();

				_path_walk(ps);

			}
			Stack<String> path;
			uint gen;
			Unification u;

			void _path_walk(Slot* ps)
			{
				int fwd;
				while ((fwd = ps->forward) < 0)
					ps = (Slot*)((long)u.ps_base - fwd);

				if ((ps->f & Edge.Flag.EtmNonBareType) != 0)
				{
					pinfo* pi = u.pbx + ps->tfsix;
					int ix = ps->uix - pi->uix0;
					int m_src = ix == 0 ? pi->tfs._top_edge.Mark : pi->entries[ix - 1].e_Mark;

					ushort* pfix = *(ushort**)((long)u.rgpfix + ((int)ps->f << 3));
					do
					{
						if ((ix = pi->_fetch_ix_only(*pfix, m_src)) != 0)
						{
							Slot* nps = (Slot*)((long)u.ps_base + ((pi->uix0 + ix) << SHL_PS));
							if (nps->gen >= gen)
							{
								path.Push(nps->_ftm[*pfix].feature);
								base.Add(path.Reverse().StringJoin(".").ToUpperInvariant() + " " + Edge.TypeInfoFromFlag(u.ftm, nps->f));
								_path_walk(nps);
								path.Pop();
							}
						}
					}
					while (*++pfix != 0xFFFF);
				}
			}
		};

		class _path_walker_x3 : HashSet<String>
		{
			public _path_walker_x3(Unification u, Slot* ps)
			{
				this.u = u;
				this.gen = u.gen;
				this.path = new Stack<string>();

				int c = u.ActiveSlots.Count;
				bool* _pb = stackalloc bool[c + 1];
				this.pb = _pb;

				_path_walk(ps);

			}
			Stack<String> path;
			uint gen;
			Unification u;
			bool* pb;

			void _path_walk(Slot* ps)
			{
				int fwd;
				while ((fwd = ps->forward) < 0)
					ps = (Slot*)((long)u.ps_base - fwd);

				if ((ps->f & Edge.Flag.EtmNonBareType) != 0 && !pb[ps->uix])
				{
					pb[ps->uix] = true;

					pinfo* pi = u.pbx + ps->tfsix;
					int ix = ps->uix - pi->uix0;
					int m_src = ix == 0 ? pi->tfs._top_edge.Mark : pi->entries[ix - 1].e_Mark;

					ushort* pfix = *(ushort**)((long)u.rgpfix + ((int)ps->f << 3));
					do
					{
						if ((ix = pi->_fetch_ix_only(*pfix, m_src)) != 0)
						{
							Slot* nps = (Slot*)((long)u.ps_base + ((pi->uix0 + ix) << SHL_PS));
							if (nps->gen >= gen && nps->gen != gen + 3)
							{
								path.Push(nps->_ftm[*pfix].feature);
								base.Add(path.Reverse().StringJoin(".").ToUpperInvariant());
								_path_walk(nps);
								path.Pop();
							}
						}
					}
					while (*++pfix != 0xFFFF);
				}
			}
		};

		public String zz22_paths_via_parent_67
		{
			get
			{
				var pw = new _path_walker_67(this, ps_base + 1);
				return pw.Count.ToString() + Environment.NewLine +
						pw.Sort().StringJoin(Environment.NewLine);
			}
		}

		class _path_walker_67 : HashSet<String>
		{
			public _path_walker_67(Unification u, Slot* ps)
			{
				this.u = u;
				this.gen = u.gen;
				this.path = new Stack<string>();

				int c = u.ActiveSlots.Count;
				bool* _pb = stackalloc bool[c + 1];
				this.pb = _pb;

				_path_walk(ps);

			}
			Stack<String> path;
			uint gen;
			Unification u;
			bool* pb;

			void _path_walk(Slot* ps)
			{
				int fwd;
				while ((fwd = ps->forward) < 0)
					ps = (Slot*)((long)u.ps_base - fwd);

				if ((ps->f & Edge.Flag.EtmNonBareType) != 0 && !pb[ps->uix])
				{
					pb[ps->uix] = true;

					pinfo* pi = u.pbx + ps->tfsix;
					int ix = ps->uix - pi->uix0;
					int m_src = ix == 0 ? pi->tfs._top_edge.Mark : pi->entries[ix - 1].e_Mark;

					ushort* pfix = *(ushort**)((long)u.rgpfix + ((int)ps->f << 3));
					do
					{
						if ((ix = pi->_fetch_ix_only(*pfix, m_src)) != 0)
						{
							Slot* nps = (Slot*)((long)u.ps_base + ((pi->uix0 + ix) << SHL_PS));
							if (nps->gen >= gen + 6)
							{
								path.Push(nps->_ftm[*pfix].feature);
								base.Add(path.Reverse().StringJoin(".").ToUpperInvariant());
								_path_walk(nps);
								path.Pop();
							}
						}
					}
					while (*++pfix != 0xFFFF);
				}
			}
		};

		SlotPtr[] _get_unif_node(Slot* ps, bool f_fwd)
		{
			if (ps == null)
				return Collection<SlotPtr>.None;

			pinfo* pi = _find_pi_for_old(ps);

			int ix = ps->uix - pi->uix0;

			Edge.Flag f = ps->gen < gen ?
				(ix == 0 ? pi->tfs._top_edge.FlagsId : pi->entries[ix - 1].e_FlagsId) & ~Edge.Flag.Coreference :
				ps->f;

			if ((f & Edge.Flag.EtmNonBareType) == 0)
				return Collection<SlotPtr>.None;

			int m_src = ix == 0 ? pi->tfs._top_edge.Mark : pi->entries[ix - 1].e_Mark;
			if (m_src == 0 || rgpfix == null)
				return Collection<SlotPtr>.None;

			ushort* pfix = *(ushort**)((long)rgpfix + ((int)f << 3));
			int c_feat = *(pfix - 1);
			SlotPtr[] arr = new SlotPtr[c_feat];
			int[] sort_keys = new int[c_feat];
			int fwd, i = 0;
			do
			{
				Slot* nps = null;
				if ((ix = pi->_fetch_ix_only(*pfix, m_src)) != 0)
				{
					nps = ps_base + (sort_keys[i] = pi->uix0 + ix);
					if (f_fwd && nps->gen >= gen)
						while ((fwd = nps->forward) < 0)
							nps = (Slot*)((long)ps_base - fwd);
				}
				arr[i] = new SlotPtr(nps);
				i++;
			}
			while (*++pfix != 0xFFFF);
			Array.Sort(sort_keys, arr);
			return arr;
		}

		public IEnumerable<IntPtr> TfsSlots(int tfsix)
		{
			if (tfsix == 0)
				return ActiveSlots;
			else if (tfsix <= c_participants)
				return (pbx + tfsix)->Slots(this);
			else
				return Enumerable.Empty<IntPtr>();
		}

		static bool _sdf_nwf(IntPtr _ps)
		{
			Slot* ps = (Slot*)_ps;
			return ps->gen >= ps->_u.gen && ps->Gen == g_nwf;
		}
		static bool _sdf_cur(IntPtr _ps)
		{
			Slot* ps = (Slot*)_ps;
			return ps->gen >= ps->_u.gen;
		}
		static bool _sdf_old(IntPtr _ps)
		{
			Slot* ps = (Slot*)_ps;
			return ps->gen < ps->_u.gen;
		}
		static bool _sdf_mst(IntPtr _ps)
		{
			Slot* ps = (Slot*)_ps;
			return ps->gen >= ps->_u.gen && ps->forward == 0;
		}
		static bool _sdf_fwd(IntPtr _ps)
		{
			Slot* ps = (Slot*)_ps;
			return ps->gen >= ps->_u.gen && ps->forward < 0;
		}
		static bool _sdf_nmf(IntPtr _ps)
		{
			Slot* ps = (Slot*)_ps;
			return ps->gen >= ps->_u.gen && ps->forward < 0 && ((Slot*)((long)ps->_u.ps_base - ps->forward))->forward < 0;
		}
		int _count_mst(int tfsix)
		{
			int _dc, c = 0;
			if (tfsix == 0)
			{
				foreach (Slot* ps in ActiveSlots)
					if (ps->IsCurrentGen && ps->forward == 0)
						c++;
			}
			else if (tfsix == -1)
				c = _count_mst(0) - _count_mst(1);
			else if (tfsix == -2)
				c = _count_mst(0) - _count_mst(1) - _count_mst(2);
			else if (tfsix > 0 && tfsix <= c_participants)
				_summary_counts(tfsix, null, out _dc, out _dc, out c, out _dc, out _dc, out _dc, null);
			return c;
		}
		/// <summary> includes non-master forwards </summary>
		int _count_fwd(int tfsix)
		{
			int _dc, c = 0;
			if (tfsix == 0)
			{
				foreach (Slot* ps in ActiveSlots)
					if (ps->IsCurrentGen && ps->forward < 0)
						c++;
			}
			else if (tfsix == -1)
				c = _count_fwd(0) - _count_fwd(1);
			else if (tfsix == -2)
				c = _count_fwd(0) - _count_fwd(1) - _count_fwd(2);
			else if (tfsix > 0 && tfsix <= c_participants)
				_summary_counts(tfsix, null, out c, out _dc, out _dc, out _dc, out _dc, out _dc, null);
			return c;
		}
		int _count_nmf(int tfsix)
		{
			int _dc, c = 0;
			if (tfsix == 0)
			{
				foreach (Slot* ps in ActiveSlots)
					if (ps->IsCurrentGen && ps->forward < 0 && ((Slot*)((long)ps_base - ps->forward))->forward < 0)
						c++;
			}
			else if (tfsix == -1)
				c = _count_nmf(0) - _count_nmf(1);
			else if (tfsix == -2)
				c = _count_nmf(0) - _count_nmf(1) - _count_nmf(2);
			else if (tfsix > 0 && tfsix <= c_participants)
				_summary_counts(tfsix, null, out _dc, out c, out _dc, out _dc, out _dc, out _dc, null);
			return c;
		}
		int _count_old(int tfsix)
		{
			int _dc, c = 0;
			if (tfsix == 0)
			{
				foreach (Slot* ps in ActiveSlots)
					if (!ps->IsCurrentGen)
						c++;
			}
			else if (tfsix == -1)
				c = _count_old(0) - _count_old(1);
			else if (tfsix == -2)
				c = _count_old(0) - _count_old(1) - _count_old(2);
			else if (tfsix > 0 && tfsix <= c_participants)
				_summary_counts(tfsix, null, out _dc, out _dc, out _dc, out c, out _dc, out _dc, null);
			return c;
		}
		int _count_gen(int tfsix, int g)
		{
			int _dc, c = 0;
			if (tfsix == 0)
			{
				uint target_gen = (uint)(this.gen + g);
				foreach (Slot* ps in ActiveSlots)
					if (ps->gen == target_gen)
						c++;
			}
			else if (tfsix == -1)
				c = _count_gen(0, g) - _count_gen(1, g);
			else if (tfsix == -2)
				c = _count_gen(0, g) - _count_gen(1, g) - _count_gen(2, g);
			else if (tfsix > 0 && tfsix <= c_participants)
			{
				if (g >= 6)
					return 0;
				int* pi = stackalloc int[6];
				_summary_counts(tfsix, null, out _dc, out _dc, out _dc, out _dc, out _dc, out _dc, pi);
				c = pi[g];
			}
			return c;
		}
		int _count_cnt(int tfsix)
		{
			int c = 0;
#if P1_COUNT
			if (tfsix == 0)
			{
				foreach (Scratch* ps in ActiveSlots)
					if (ps->IsCurrentGen)
						c += ps->c_cnt;
			}
			else if (tfsix == -1)
				c = _count_cnt(0) - _count_cnt(1);
			else if (tfsix == -2)
				c = _count_cnt(0) - _count_cnt(1) - _count_cnt(2);
			else if (tfsix > 0 && tfsix <= c_participants)
			{
				foreach (Scratch* ps in TfsSlots(tfsix))
					if (ps->IsCurrentGen)
						c += ps->c_cnt;
			}
#endif
			return c;
		}
		String _summary_counts(int tfsix, Func<IntPtr, bool> filter)
		{
			if (tfsix > c_participants)
				return "(err)";

			int fwd;
			int nmf;
			int mst;
			int old;
			int tot;
			int cnt;
			int* pi = stackalloc int[6];
			_summary_counts(tfsix, filter, out fwd, out nmf, out mst, out old, out cnt, out tot, pi);
			String s = "";
			if (tot > 0)
			{
				if (old != 0)
					s = old.ToString().PadLeft(3) + " <";
				else
					s = "     ";

				s += String.Format(" {{{0,4}{1,4}{2,4}{3,4}{4,4}{5,4}}} C:{6,-4} {7,-6}{8,-9}",
					pi[0] == 0 ? "." : pi[0].ToString(),
					pi[1] == 0 ? "." : pi[1].ToString(),
					pi[2] == 0 ? "." : pi[2].ToString(),
					pi[3] == 0 ? "." : pi[3].ToString(),
					pi[4] == 0 ? "." : pi[4].ToString(),
					pi[5] == 0 ? "." : pi[5].ToString(),
					cnt,//cnt == 0 ? "." : cnt.ToString(),
					mst == 0 ? "" : "M:" + mst.ToString(),
					fwd == 0 ? "" : "F:" + fwd.ToString() + (nmf == 0 ? "" : "/" + nmf));

				//s += (cnt == 0 ? "" : "cnt:" + cnt).PadRight(8);
			}
			s += "Σ:" + tot.ToString().PadRight(3);
			return s;
		}

		void _summary_counts(int tfsix, Func<IntPtr, bool> filter, out int cfwd, out int cnmf, out int cmst, out int cold, out int ccnt, out int tot, int* pi_out)
		{
			cfwd = 0;
			cmst = 0;
			cold = 0;
			cnmf = 0;
			ccnt = 0;
			tot = 0;
			if (tfsix < 0 || tfsix > c_participants)
				return;
			foreach (Slot* ps in tfsix == 0 ? ActiveSlots : (pbx + tfsix)->Slots(this))
			{
				if (filter == null || filter((IntPtr)ps))
				{
					tot++;
					if (!ps->IsCurrentGen)
						cold++;
					else
					{
#if P1_COUNT
						ccnt += ps->c_cnt;
#endif
						int g = ps->Gen;
						if (g >= GEN_INCR)
							throw new Exception();
						if (pi_out != null)
							pi_out[g]++;

						int fwd;
						if ((fwd = ps->forward) == 0)
							cmst++;
						else if (fwd > 0)
							throw new Exception();
						else
						{
							cfwd++;
							if (((Slot*)((long)ps_base - fwd))->forward < 0)
								cnmf++;
						}
					}
				}
			}
		}

		int _coref_tot(int tfsix)
		{
			int ctot = 0, cnul, cmst, cfwd, cnmf, cind, ccnt;
			if (tfsix == 0)
				_coref_totals(out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			else if (tfsix == -1)
				return _coref_tot(0) - _coref_tot(1);
			else if (tfsix == -2)
				return _coref_tot(0) - _coref_tot(1) - _coref_tot(2);
			else if (tfsix > 0 && tfsix <= c_participants)
				(pbx + tfsix)->CorefCounts(this, out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			return ctot;
		}
		int _coref_nul(int tfsix)
		{
			int ctot, cnul = 0, cmst, cfwd, cnmf, cind, ccnt;
			if (tfsix == 0)
				_coref_totals(out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			else if (tfsix == -1)
				return _coref_nul(0) - _coref_nul(1);
			else if (tfsix == -2)
				return _coref_nul(0) - _coref_nul(1) - _coref_nul(2);
			else if (tfsix > 0 && tfsix <= c_participants)
				(pbx + tfsix)->CorefCounts(this, out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			return cnul;
		}
		int _coref_mst(int tfsix)
		{
			int ctot, cnul, cmst = 0, cfwd, cnmf, cind, ccnt;
			if (tfsix == 0)
				_coref_totals(out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			else if (tfsix == -1)
				return _coref_mst(0) - _coref_mst(1);
			else if (tfsix == -2)
				return _coref_mst(0) - _coref_mst(1) - _coref_mst(2);
			else if (tfsix > 0 && tfsix <= c_participants)
				(pbx + tfsix)->CorefCounts(this, out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			return cmst;
		}
		int _coref_fwd(int tfsix)
		{
			int ctot, cnul, cmst, cfwd = 0, cnmf, cind, ccnt;
			if (tfsix == 0)
				_coref_totals(out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			else if (tfsix == -1)
				return _coref_fwd(0) - _coref_fwd(1);
			else if (tfsix == -2)
				return _coref_fwd(0) - _coref_fwd(1) - _coref_fwd(2);
			else if (tfsix > 0 && tfsix <= c_participants)
				(pbx + tfsix)->CorefCounts(this, out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			return cfwd;
		}
		int _coref_nmf(int tfsix)
		{
			int ctot, cnul, cmst, cfwd, cnmf = 0, cind, ccnt;
			if (tfsix == 0)
				_coref_totals(out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			else if (tfsix == -1)
				return _coref_nmf(0) - _coref_nmf(1);
			else if (tfsix == -2)
				return _coref_nmf(0) - _coref_nmf(1) - _coref_nmf(2);
			else if (tfsix > 0 && tfsix <= c_participants)
				(pbx + tfsix)->CorefCounts(this, out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			return cnmf;
		}
		int _coref_ind(int tfsix)
		{
			int ctot, cnul, cmst, cfwd, cnmf, cind = 0, ccnt;
			if (tfsix == 0)
				_coref_totals(out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			else if (tfsix == -1)
				return _coref_nmf(0) - _coref_nmf(1);
			else if (tfsix == -2)
				return _coref_nmf(0) - _coref_nmf(1) - _coref_nmf(2);
			else if (tfsix > 0 && tfsix <= c_participants)
				(pbx + tfsix)->CorefCounts(this, out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			return cind;
		}
		int _coref_cnt(int tfsix)
		{
			int ctot, cnul, cmst, cfwd, cnmf, cind, ccnt = 0;
			if (tfsix == 0)
				_coref_totals(out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			else if (tfsix == -1)
				return _coref_cnt(0) - _coref_cnt(1);
			else if (tfsix == -2)
				return _coref_cnt(0) - _coref_cnt(1) - _coref_cnt(2);
			else if (tfsix > 0 && tfsix <= c_participants)
				(pbx + tfsix)->CorefCounts(this, out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
			return ccnt;
		}
		void _coref_totals(out int _ctot, out int _cnul, out int _cmst, out int _cfwd, out int _cnmf, out int _cind, out int _ccnt)
		{
			_ctot = 0; _cnul = 0; _cmst = 0; _cfwd = 0; _cnmf = 0; _cind = 0; _ccnt = 0;

			for (int i = 1; i <= c_participants; i++)
			{
				int ctot, cnul, cmst, cfwd, cnmf, cind, ccnt;
				(pbx + i)->CorefCounts(this, out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);

				_ctot += ctot; _cnul += cnul; _cmst += cmst; _cfwd += cfwd; _cnmf += cnmf; _cind += cind; _ccnt += ccnt;
			}
			if (c_corefs != _ctot)
				throw new Exception();
		}

		public String ShortInfo0a(Slot* ps)
		{
			if (!ps->IsCurrentGen)
				return "(old)";

			int tfsix = ps->tfsix;
			pinfo* pi = pbx + tfsix;
			String s = String.Format("{0}@{1}", tfsix, ps->uix - pi->uix0);

			int mix = ps->uix - pi->uix0;
			if (mix < 0)
				s += String.Format("({0})", mix.ToString());
			else if (mix > 0)
			{
				arr_tfs_entry ate;
				pi->tfs.GetIndexData(mix, &ate);
				s += String.Format("({0})", ate.FeatMark.ShortDisplay(ps->_ftm));
			}
			return s;
		}
		public String ShortInfo1(Slot* ps)
		{
			int tfsix = ps->tfsix;
			int uix = ps->uix;
			return String.Format("{0,3}:{1}.{2,-3}", uix, tfsix, uix - (pbx + tfsix)->uix0);
		}
		public String ShortInfo1a(Slot* ps)
		{
			int tfsix = ps->tfsix;
			int uix = ps->uix;
			return String.Format("{0}:{1}.{2}", uix, tfsix, uix - (pbx + tfsix)->uix0);
		}
		public String ShortInfo2(Slot* ps)
		{
			String s = ShortInfo0a(ps);
			if (ps->gen >= gen)
			{
				if (ps->forward == 0)
					s += " " + Edge.TypeInfoFromFlag(ftm, ps->f);
				else
					s += "m" + ps->m_src;
			}
			return s;
		}

		public override String ToString()
		{
			String s = String.Format("TFSes:{0}  Active slots: {1}  ", c_participants, ActiveSlots.Count);
			if (stk != null)
				s += "\"" + CurrentPath + "\"";
			if (_ps0 != null && _ps1 != null)
			{
				s += String.Format("  {0} ⊓ {1}",
					"{" + ShortInfo2(_ps0) + "}",
					"{" + ShortInfo2(_ps1) + "}");
			}
			return s;
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		void _dbg_count_display(Slot* ps, int c_test, int c_reference)
		{
			//while (true)
			//{
			//    if ((opts & (Tfs.Flags.DeleteArgs | Tfs.Flags.Restrict)) == 0)
			//        break;

			//    if ((opts & Tfs.Flags.DeleteArgs) != 0 && (opts & Tfs.Flags.Restrict) != 0)
			//        break;

			//    if ((opts & Tfs.Flags.DeleteArgs) != 0 && (opts & Tfs.Flags.Restrict) == 0)
			//        break;

			//    if ((opts & Tfs.Flags.DeleteArgs) == 0 && (opts & Tfs.Flags.Restrict) != 0)
			//        break;

			//    goto no_report;
			//}

			//if (_count != newcount)
			//{
			//    Console.Out.WriteColor("[$cyan i:{0} f:{1}", _count, newcount);
			//    Console.Write(" ({0})] ", count);
			//}

			Console.Out.WriteColor("$cyan {0}", c_participants);
			if ((opts & Tfs.Flags.DeleteArgs) != 0)
				Console.Write('d');
			if ((opts & Tfs.Flags.Restrict) != 0)
				Console.Write('r');
			Console.Write(" {0} ", ps->tfsix);

			int d = 0;
			if (c_test == -1)
			{
				Console.Out.WriteColor("$white ?$ ({0})", c_reference);
			}
			else
			{
				d = c_test - c_reference;
				if (d == 0)
					Console.Out.WriteColor("$green " + c_reference);
				else if (d < 0)
					Console.Out.WriteColor("$red {0}$ ({1}, {2})", c_test, c_reference, d);
				else
					Console.Out.WriteColor("$yellow {0}$ ({1}, +{2})", c_test, c_reference, d);
			}

			const int wid = 24;
			if (Console.CursorLeft != 0)
			{
				int rem = (wid - 1) - Console.CursorLeft % wid;
				if (Console.CursorLeft + rem + wid >= Console.BufferWidth)
					Console.WriteLine();
				else if (rem > 0)
					Console.Write(new String(' ', rem));
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		class debug_coref_map_class
		{
			public debug_coref_map_class(Unification u)
			{
				this.u = u;
			}
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			Unification u;

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			debug_coref_list[] _dbg_rgrg_corefs
			{
				get
				{
					debug_coref_list[] rgrg = new debug_coref_list[u.c_participants + 3];
					for (int i = 0; i < rgrg.Length; i++)
						if (i == 0)
							rgrg[i] = new debug_coref_list_x1(u);
						else if (i == 1)
							rgrg[i] = new debug_coref_list_x2(u);
						else if (i == 2)
							rgrg[i] = new debug_coref_list_sep(u);
						else
							rgrg[i] = new debug_coref_list_a(new u_pinfo(u, u.pbx + (i - 2)));
					return rgrg;
				}
			}

			public override String ToString()
			{
				try
				{
					int ctot, cnul, cmst, cfwd, cnmf, cind, ccnt;
					u._coref_totals(out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
					return String.Format("TFSes:{0,-2} {1}", u.c_participants, debug_coref_list.format(ctot, cnul, cmst, cfwd, cnmf, cind, ccnt));
				}
				catch (Exception ex)
				{
					return ex.ToString() + Environment.NewLine + ex.StackTrace.ToString();
				}
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("         {ToString(),nq}", Name = "{description,nq}")]
		abstract class debug_coref_list
		{
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public Unification u;

			public debug_coref_list(Unification u)
			{
				this.u = u;
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public abstract String description { get; }

			public static String format(int ctot, int cnul, int cmst, int cfwd, int cnmf, int cind, int ccnt)
			{
				return String.Format("tot:{0,-3} {{ {1} {2} {3} {4} {5} }}",
					ctot,
					(cnul == 0 ? "" : "nul:" + cnul.ToString()).PadRight(7),
					(cmst == 0 ? "" : "mst:" + cmst.ToString()).PadRight(7),
					(cfwd == 0 ? "" : "fwd:" + cfwd.ToString()).PadRight(7),
					(cnmf == 0 ? "" : "nmf:" + cnmf.ToString()).PadRight(7),
					(cind == 0 ? "" : "ind:" + cind.ToString()).PadRight(7),
					(ccnt == 0 ? "" : "cnt:" + ccnt.ToString()).PadRight(7));
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		class debug_coref_list_sep : debug_coref_list
		{
			public debug_coref_list_sep(Unification u)
				: base(u)
			{
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public override String description { get { return "   ----------------"; } }

			public override String ToString() { return description; }
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		class debug_coref_list_x1 : debug_coref_list
		{
			public debug_coref_list_x1(Unification u)
				: base(u)
			{
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public override String description
			{
				get { return "Except TFS 1"; }
			}

			public override String ToString()
			{
				return "   " + format(u._coref_tot(-1), u._coref_nul(-1), u._coref_mst(-1), u._coref_fwd(-1), u._coref_nmf(-1), u._coref_ind(-1), u._coref_cnt(-1));
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		class debug_coref_list_x2 : debug_coref_list
		{
			public debug_coref_list_x2(Unification u)
				: base(u)
			{
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public override String description
			{
				get { return "Except TFSes 1 & 2"; }
			}

			public override String ToString()
			{
				return "   " + format(u._coref_tot(-2), u._coref_nul(-2), u._coref_mst(-2), u._coref_fwd(-2), u._coref_nmf(-2), u._coref_ind(-2), u._coref_cnt(-2));
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("         {ToString(),nq}", Name = "{description,nq}")]
		[DebuggerTypeProxy(typeof(dbg_type_proxy))]
		class debug_coref_list_a : debug_coref_list
		{
			public debug_coref_list_a(u_pinfo upi)
				: base(upi.u)
			{
				this.upi = upi;
			}
			public u_pinfo upi;

			public class dbg_type_proxy
			{
				public dbg_type_proxy(debug_coref_list_a dca)
				{
					this.upi = dca.upi;
				}
				u_pinfo upi;

				[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
				public dbg_coref_map_entry[] _dbg_coref_map
				{
					get
					{
						try
						{
							int cc;
							if ((cc = upi.tfs.c_corefs) == 0)
								return alib.Collections.Collection<dbg_coref_map_entry>.None;
							dbg_coref_map_entry[] rg = new dbg_coref_map_entry[cc];
							Slot** pps = upi.pi->coref_designations + 1;
							int m = -1;
							for (int i = 0; i < rg.Length; i++)
							{
								rg[i] = new dbg_coref_map_entry(m, upi, *pps);
								pps++;
								m--;
							}
							return rg;
						}
						catch (Exception ex)
						{
							Debug.Print("{0}\r\n\r\n{1}", ex.ToString(), ex.StackTrace.ToString());
							return null;
						}
					}
				}
			};

			public override String description
			{
				get { return String.Format("{0,4} {1}", upi.pi->tfsix.ToString(), upi.tfs.ToString()); }
			}

			public override String ToString()
			{
				try
				{
					int ctot, cnul, cmst, cfwd, cnmf, cind, ccnt;
					upi.pi->CorefCounts(u, out ctot, out cnul, out cmst, out cfwd, out cnmf, out cind, out ccnt);
					return "   " + format(ctot, cnul, cmst, cfwd, cnmf, cind, ccnt);
				}
				catch (Exception ex)
				{
					return ex.ToString();
				}

			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}", Name = "{_dbg_dsc(),nq}  ⇌{for_coref.ToString().PadRight(4),nq}")]
		struct dbg_coref_map_entry
		{
			public dbg_coref_map_entry(int for_coref, u_pinfo upi, Slot* ps)
			{
				this.for_coref = for_coref;
				this.upi = upi;
				this.ps = ps;
			}
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			int for_coref;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			u_pinfo upi;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			Slot* ps;

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			public ScratchDebugCorefBaseClass _dbg
			{
				get
				{
					if (ps == null)
						return new ScratchDebugClassNullCoref(upi, for_coref);
					return new ScratchDebugClassNorm(upi, for_coref, ps);
				}
			}

			public String _dbg_dsc()
			{
				String s;
				if (upi == null || ps == null)
					s = "";
				else
					s = "[" + upi.u.ShortInfo1a(ps) + "]";
				return s.PadLeft(12);
			}

			public override String ToString()
			{
				if (ps == null)
					return "  (null)";
				if (ps == upi.u.ps_base)
					return "(ps_base)";
				if (ps->gen < upi.u.gen)
					return "(old)";
				return new SlotPtr(ps).ToStringEx(false);
			}
		};

		public abstract class ScratchDebugCorefBaseClass
		{
			public ScratchDebugCorefBaseClass(u_pinfo upi, int for_coref)
			{
				this.upi = upi;
				this.for_coref = for_coref;
			}
			protected u_pinfo upi;
			protected int for_coref;
		};

		[DebuggerDisplay("{ToString(),nq}", Name = "{(\"[\"+ps->_thisix.ToString()+\"]\").PadLeft(23),nq}")]
		[DebuggerTypeProxy(typeof(dbg_type_proxy))]
		public class ScratchDebugClassNorm : ScratchDebugCorefBaseClass
		{
			public ScratchDebugClassNorm(u_pinfo upi, int for_coref, Slot* ps)
				: base(upi, for_coref)
			{
				this.sd = new SlotPtr(ps);
			}
			SlotPtr sd;

			public class dbg_type_proxy
			{
				public dbg_type_proxy(ScratchDebugClassNorm sdn)
				{
					this.sdn = sdn;
				}
				ScratchDebugClassNorm sdn;

				[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
				public SlotPtr _sd { get { return sdn.sd; } }
			};

			public override string ToString() { return sd.ToString(); }
		};

		[DebuggerTypeProxy(typeof(dbg_type_proxy))]
		public class ScratchDebugClassNullCoref : ScratchDebugCorefBaseClass
		{
			public ScratchDebugClassNullCoref(u_pinfo upi, int for_coref)
				: base(upi, for_coref)
			{
			}

			public class dbg_type_proxy
			{
				public dbg_type_proxy(ScratchDebugClassNullCoref sdn)
				{
					this.sdn = sdn;
				}
				ScratchDebugClassNullCoref sdn;

#if REVERSE_INDEX
				[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
				public SlotPtr[] rgsd
				{
					get
					{
						Unification u = sdn.upi.u;
						pinfo* pi = sdn.upi.pi;
						return pi->tfs.GetOutMarkSlots(sdn.for_coref)
									.Select(ix => new SlotPtr(u.ps_base + (pi->uix0 + ix)))
									.ToArray();
					}
				}
#endif
			};
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// tfsix : index of the TFS in participants[...]
		/// rix : raw, mixed index within a single TFS
		/// mix : mixed index adjusted to be referenced off bases[tfsix]
		///			'mark' if less than zero. it is always valid to reference bases[tfsix]+mix with it
		/// gix : global index of any Scratch field, based only on ps_base
		///			global slot 0 is reserved for indicating 'no forwarding'
		/// ps : pointer to scratch structures
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}", Name = "{dbg_info(),nq}")]
		public struct SlotPtr : IEquatable<SlotPtr>
		{
			[DebuggerStepThrough]
			public SlotPtr(Slot* ps)
			{
				this.ps = ps;
			}

			[DebuggerStepThrough]
			public SlotPtr(IntPtr ps)
			{
				this.ps = (Slot*)ps;
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public Slot* ps;

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public Unification u
			{
				get { return (Unification)((GCHandle*)((long)ps - ((ps->uix + 1) << SHL_PS)))->Target; }
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public pinfo* pi
			{
				get
				{
					if (ps == null)
						return null;
					var u = (Unification)((GCHandle*)((long)ps - ((ps->uix + 1) << SHL_PS)))->Target;
					return u.pbx + ps->tfsix;
				}
			}

			public void test()
			{

				Debug.Print("2");
				var x1 = z1_unifier_node;
				Debug.Print("3");
				var x2 = z1a_unifier_node;
				Debug.Print("4");
#if REVERSE_INDEX
				var x3 = z2_paths;
				Debug.Print("5");
				var x4 = z2a_paths_local;
				Debug.Print("6");
#endif
				var x5 = z3_fwd_target;
				Debug.Print("7");
				var x6 = z4_references;
				Debug.Print("8");
				var x7 = z5_forwarders;
				Debug.Print("9");
#if REVERSE_INDEX
				var x8 = z6_tfs_upper;
				Debug.Print("10");
				var x9 = z7_tfs_paths;
				Debug.Print("11");
#endif
				var x10 = z8_tfs_node;
				Debug.Print("12");
				var x11 = z9_tfs;
				Debug.Print("13");
				var x12 = z1_info();
				Debug.Print("14");
				var x13 = z1a_info();
				Debug.Print("15");
#if REVERSE_INDEX
				var x14 = z2_info();
				Debug.Print("16");
				var x15 = z2a_info();
#endif
				Debug.Print("17");
				var x16 = z3_info();
				Debug.Print("18");
				var x17 = z4_info();
			}

			String dbg_info()
			{
				String s;
				if (ps == null)
					s = "(null)";
				else
				{
					pinfo* pi = u._find_pi_for_old(ps);
					int uix = ps->uix;
					int ix = uix - pi->uix0;
					s = String.Format("{0}:{1}.{2,-3}", uix, pi->tfsix, ix);
				}
				return s.PadLeft(10);
			}

			[DebuggerDisplay("=========  {z1_info(),nq}", Name = "unifier node")]
			public SlotPtr[] z1_unifier_node
			{
				get
				{
					Unification u = this.u;
					if (u == null)
						return Collection<SlotPtr>.None;
					Slot* psm = ps;
					if (psm->gen >= u.gen)
					{
						int fwd;
						while ((fwd = psm->forward) < 0)
							psm = (Slot*)((long)u.ps_base - fwd);
					}
					return u._get_unif_node(psm, true);
				}
			}
			String z1_info()
			{
				Unification u = this.u;
				if (u == null || ps == null)
					return "";
				if (ps->gen < u.gen)
					return String.Format("(old, showing slots for {0})", s_tfs());
				if (ps->forward == 0)
					return String.Format("{0}", Edge.TypeInfoFromFlag(ps->_ftm, ps->f));

				Slot* psm = ps;
				int fwd;
				while ((fwd = psm->forward) < 0)
					psm = (Slot*)((long)u.ps_base - fwd);
				return String.Format("(→ [{0}] {1})", u.ShortInfo1(psm), Edge.TypeInfoFromFlag(ps->_ftm, psm->f));
			}

			[DebuggerDisplay("=========  {z1a_info(),nq}", Name = "unifier node (local)")]
			public SlotPtr[] z1a_unifier_node
			{
				get
				{
					Unification u = this.u;
					if (u == null)
						return Collection<SlotPtr>.None;
					return u._get_unif_node(ps, false);
				}
			}
			String z1a_info()
			{
				Unification u = this.u;
				if (u == null || ps == null)
					return "";
				if (ps->gen < u.gen)
					return "(old)";

				String s = String.Format("{0}", Edge.TypeInfoFromFlag(ps->_ftm, ps->f));

				Slot* psm = ps;
				int fwd;
				if ((fwd = psm->forward) < 0)
				{
					do
						psm = (Slot*)((long)u.ps_base - fwd);
					while ((fwd = psm->forward) < 0);
					return s += String.Format(" (→ [{0}] {1})", u.ShortInfo1(psm), Edge.TypeInfoFromFlag(ps->_ftm, psm->f));
				}
				return s;
			}

#if REVERSE_INDEX
			[DebuggerDisplay("=========  {z2_info(),nq}", Name = "unifier paths")]
			UnifierPath[] z2_paths
			{
				get
				{
					Unification u = this.u;
					if (u == null || ps == null || ps->gen < u.gen)
						return Collection<UnifierPath>.None;
					Slot* psm = ps;
					int fwd;
					while ((fwd = psm->forward) < 0)
						psm = (Slot*)((long)u.ps_base - fwd);
					return u.UnifierPaths(psm);
				}
			}
			String z2_info()
			{
				Unification u = this.u;
				if (u == null || ps == null)
					return "";
				if (ps->gen < u.gen)
					return "(old)";

				String s = "";

				Slot* psm = ps;
				int fwd;
				if ((fwd = psm->forward) < 0)
				{
					do
						psm = (Slot*)((long)u.ps_base - fwd);
					while ((fwd = psm->forward) < 0);
					s = String.Format("(→ [{0}]) ", u.ShortInfo1(psm));
				}

				var L = u.UnifierPaths(psm);
				if (L.Length == 0)
					return s.TrimEnd();
				return s + (L.Length == 1 ? L[0].ToString() : L.Length + " paths");
			}

			[DebuggerDisplay("=========  {z2a_info(),nq}", Name = "unifier paths (local)")]
			UnifierPath[] z2a_paths_local
			{
				get
				{
					Unification u = this.u;
					if (u == null || ps == null || ps->gen < u.gen)
						return Collection<UnifierPath>.None;
					return u.UnifierPaths(ps);
				}
			}
			String z2a_info()
			{
				Unification u = this.u;
				if (u == null || ps == null)
					return "";
				if (ps->gen < u.gen)
					return "(old)";

				String s = "";
				var L = u.UnifierPaths(ps);
				if (L.Length == 0)
					return s.TrimEnd();
				return s + (L.Length == 1 ? L[0].ToString() : L.Length + " paths");
			}
#endif

			[DebuggerDisplay("=========  {z3_info(),nq}", Name = "forwarded to")]
			public SlotPtr[] z3_fwd_target
			{
				get
				{
					try
					{
						Unification u = this.u;
						if (u == null || ps == null || ps->gen < u.gen || ps->forward == 0)
							return Collection<SlotPtr>.None;
						Slot* ps_fwd = ps;
						int fwd;
						while ((fwd = ps_fwd->forward) < 0)
							ps_fwd = (Slot*)((long)u.ps_base - fwd);
						return new SlotPtr[] { new SlotPtr(ps_fwd) };
					}
					catch (Exception ex)
					{
						Debug.Print("{0}\r\n{1}", ex.ToString(), ex.StackTrace.ToString());
						return Collection<SlotPtr>.None;
					}
				}
			}
			String z3_info()
			{
				Unification u = this.u;
				if (u == null || ps == null || ps->gen < u.gen)
					return "";
				if (ps->forward == 0)
					return String.Format("(master) {0}/{1} refs",
						u._total_forwarders((IntPtr)ps),
						u._immediate_forwarders((IntPtr)ps));
				Slot* ps_fwd = ps;
				int fwd;
				while ((fwd = ps_fwd->forward) < 0)
					ps_fwd = (Slot*)((long)u.ps_base - fwd);
				return ps_fwd->ToString().TrimStart();
			}

			[DebuggerDisplay("=========  {z4_info(),nq}", Name = "joined with")]
			public ForwardChainSet[] z4_references
			{
				get
				{
					try
					{
						Unification u = this.u;
						if (u == null || ps == null || ps == u.ps_base || ps->gen < u.gen)
							return Collection<ForwardChainSet>.None;
						return u.active_forwarders(u._ps_master(ps));
					}
					catch (Exception ex)
					{
						Debug.Print("{0}\r\n{1}", ex.ToString(), ex.StackTrace.ToString());
						return null;
					}
				}
			}
			String z4_info()
			{
				Unification u = this.u;
				if (u == null || ps == null || ps->gen < u.gen)
					return "";
				if (ps->tfsix <= 0)
					return "(ps->tfsix<=0)";

				Slot* psm = u._ps_master(ps);
				if (psm == null)
					return "(null master)";
				Unification uu = u;
				return u.fwd_chains((IntPtr)psm)
							.Where(cip => cip.Count > 1)
							.Select(seq => uu._format_forward_chain(seq).TrimStart())
							.StringJoin("  ");
			}

			[DebuggerDisplay("=========  ", Name = "all nodes")]
			public SlotPtr[] z5_forwarders
			{
				get
				{
					Unification u = this.u;
					if (u == null || ps == null || ps->gen < u.gen)
						return Collection<SlotPtr>.None;
					Slot* ps_fwd = ps;
					int fwd;
					while ((fwd = ps_fwd->forward) < 0)
						ps_fwd = (Slot*)((long)u.ps_base - fwd);
					return u._all_forwarders_and_self((IntPtr)ps_fwd).Select(x => new SlotPtr(x)).ToArray();
				}
			}

			String s_tfs()
			{
				Unification u = this.u;
				return u == null || ps == null ? "" : "tfs #" + u._find_pi_for_old(ps)->tfsix.ToString();
			}

#if REVERSE_INDEX
			[DebuggerDisplay("=========  {z6_tfs_upper.Length} slots", Name = "{s_tfs(),nq} upper slots")]
			public SlotPtr[] z6_tfs_upper
			{
				get
				{
					Unification u = this.u;
					return u == null || ps == null ? Collection<SlotPtr>.None : u._tfs_parent_slots_sd(ps);
				}
			}

			[DebuggerDisplay("=========  {z7_tfs_paths.Length} paths", Name = "{s_tfs(),nq} paths")]
			public Ix1Path[] z7_tfs_paths
			{
				get
				{
					Tfs atfs;
					int ix;
					//TypeMgr tm = u._get_slot_tm(ps);
					pinfo* pi = this.pi;
					if (pi == null)
						pi = u._find_pi_for_old(ps);
					if (pi == null || (atfs = pi->tfs) == null || (ix = ps->uix - pi->uix0) == 0)
						return Collection<Ix1Path>.None;
					int m = pi->entries[ix - 1].e_Mark;
					return m < 0 ? atfs.OutMarkPaths(ps->_ftm, m) : atfs.Ix1Paths(ix);
				}
			}
#endif

			[DebuggerDisplay("=========  {z8_tfs_node.ToString(),nq}", Name = "{s_tfs(),nq} local node")]
			public TfsSlot z8_tfs_node
			{
				get
				{
					try
					{
						Unification u = this.u;
						if (u == null || ps == null)
							return default(TfsSlot);
						pinfo* pi = u._find_pi_for_old(ps);
						if (pi == null)
							return default(TfsSlot);
						int ix;
						var atfs = pi->tfs;
						if (atfs == null || (ix = ps->uix - pi->uix0) == 0)
							return default(TfsSlot);
						return new TfsSlot(atfs, ix - 1);
					}
					catch (Exception ex)
					{
						Debug.Print("{0}\r\n{1}", ex.ToString(), ex.StackTrace.ToString());
						return default(TfsSlot);
					}
				}
			}

			[DebuggerDisplay("=========  {z9_tfs.ToString(),nq}", Name = "{s_tfs(),nq}")]
			public Tfs z9_tfs
			{
				get
				{
					Unification u = this.u;
					pinfo* _pbx;
					return u == null || ps == null || (_pbx = u.pbx) == null ? null : u._find_pi_for_old(ps)->tfs;
				}
			}

			public override String ToString()
			{
				try
				{
					return ToStringEx(false);
				}
				catch (Exception ex)
				{
					return String.Format("{0}\r\n\r\n{1}", ex.ToString(), ex.StackTrace.ToString());
				}
			}

			public String ToStringEx(bool f_show_index)
			{
				if (ps == null)
					return "(null)";

				if (ps->tfsix <= 0)
					return "(ps->tfsix<=0)";

				Unification u = this.u;
				if (u == null)
					return "(null unifier)";

				pinfo* pi = this.pi;
				if (pi == null || pi->tfsix != ps->tfsix)
					return "(pi error)";

				int uix = ps->uix;
				int ix1 = uix - pi->uix0;
				Slot* ps_master = u._ps_master(ps);

				var atfs = pi->tfs;
				if (atfs == null)
					return "(null tfs)";

				arr_tfs_entry ate;
				atfs.GetIndexData(ix1, &ate);
				Edge.Flag ef_tfs = ate.e.FlagsId & ~Edge.Flag.Coreference;
				bool f_designated_coref = ps == *(pi->coref_designations - ate.e.Mark);

				String s = f_show_index ? String.Format("{0} ", u.ShortInfo1(ps)) : "";

				FeatMgr ftm = u.ftm;
				if (ftm == null)
				{
					s += "(no TypeMgr)";
					return s;
				}

				if (atfs is MultiRootTfs || atfs is TfsBuilder.Xdl)
					s += ftm.Grammar.Name.PadRight(5);

				String fs = "";
				if (ix1 == 0)
					fs += "TOPMST";
				else if (ate.mark != 0)
					fs += ate.mark + "/" + ftm.feat_arr[ate.i_feat].feature.ToUpper();

				s += fs.PadRight(15);

				s += (/*(f_designated_coref ? "" : " ") +*/ u._format_ps(ps, false)).PadRightComb(4);

				Slot* ps_tf = null;
				String mm = "";
				String scnt = "";

				int g = ps->Gen;
				if (g >= 0 && ftm != null)
				{
					int fwd = ps->forward;
					if (fwd > 0)
						mm += "ERR: fwd==" + fwd;
					else
					{
						if (fwd == 0)
						{
							String qq = "M ";
							qq += u._fcd(ps, false);
							mm += qq;
							ps_tf = ps;
#if UNIF_V6
							if (g >= 6)
								mm = mm.PadRightComb(25) + " " + (ps->m_src == 0 ? "□" : ps->m_src < 0 ? Edge.Chars.Coref + (-ps->m_src) : "@" + ps->m_src);
#endif
						}
						else
						{
							mm += u._forward_chain_display(ps, true);
							ps_tf = ps_master;
						}
					}

#if P1_COUNT
					if (ps->c_cnt > 0)
						scnt = String.Format("c:{0}", ps->c_cnt);
					scnt = scnt.PadRight(5);
#endif
					int c_fwd_tot = u._total_forwarders((IntPtr)ps);
					scnt += (c_fwd_tot == 0 ? "" : "f:" + c_fwd_tot.ToString()).PadLeft(4) + " ";

					int c_feat;
					if ((ps->f & Edge.Flag.EtmNonBareType) == 0)
						c_feat = 0;
					else
					{
						ushort* _rgpfix = *(ushort**)((long)u.rgpfix + ((int)ps->f << 3));
						c_feat = _rgpfix[-1];

						scnt += (c_feat == 0 ? "" : c_feat.ToString()).PadLeft(2) + " ";

						int standalone_feat_count = ps->_count_func(u, _rgpfix);
						scnt += (standalone_feat_count == 0 ? "" : standalone_feat_count.ToString()).PadLeft(2) + " ";
					}
				}

				s += mm.LeftRightComb(scnt, 55) + " ";

				mm = "";
				if (ps_tf != null)
					mm = " " + Edge.TypeInfoFromFlag(ps_tf->_ftm, ps_tf->f);
				s += mm.PadRight(25);

				if (ps_tf == null || ef_tfs != ps_tf->f || ate.e.Mark != 0)
				{
					s += " (";
					if (ps_tf == null || ef_tfs != ps_tf->f)
					{
						if (ef_tfs == 0)
							s += Edge.Chars.Top;
						else
							s += ftm.tu.TypeNameOrStringValue(ef_tfs) + ((ef_tfs & Edge.Flag.EtmNonBareType) != 0 ? Edge.Chars.Complex : "");
						if (ate.e.Mark != 0)
							s += " ";
					}
					if (ate.e.Mark < 0)
						s += Edge.Chars.Coref + (-ate.e.Mark);
					else if (ate.e.Mark > 0)
						s += ate.e.Mark;
					s += ")";
				}
				return s;
			}

			public bool Equals(SlotPtr other)
			{
				return other.ps == this.ps;
			}

			public override bool Equals(object obj)
			{
				return obj is SlotPtr && ((SlotPtr)obj).ps == this.ps;
			}

			public override int GetHashCode()
			{
				return (int)this.ps;
			}
		};

		public SlotPtr[] ToSdArray(List<IntPtr> rguix)
		{
			SlotPtr[] arr = new SlotPtr[rguix.Count];
			for (int i = 0; i < arr.Length; i++)
				arr[i] = new SlotPtr(rguix[i]);
			return arr;
		}

		public SlotPtr[] ToSdArray(IntPtr[] rguix)
		{
			SlotPtr[] arr = new SlotPtr[rguix.Length];
			for (int i = 0; i < rguix.Length; i++)
				arr[i] = new SlotPtr(rguix[i]);
			return arr;
		}
		/// <summary>
		/// ...or self (only 'null' for old or nul arg)
		/// </summary>
		public Slot* _ps_master(Slot* ps)
		{
			if (ps == null || ps->gen < this.gen)
				return null;
			int fwd;
			while ((fwd = ps->forward) < 0)
				ps = (Slot*)((long)ps_base - fwd);
			return ps;
		}
		/// <summary>
		/// ...or self (returns self for 'old' too; only 'null' for IntPtr.Zero arg)
		/// </summary>
		public IntPtr _ps_master(IntPtr ps)
		{
			if (ps == IntPtr.Zero)
				return IntPtr.Zero;
			if (((Slot*)ps)->gen < this.gen)
				return ps;
			int fwd;
			while ((fwd = ((Slot*)ps)->forward) < 0)
				ps = (IntPtr)((long)ps_base - fwd);
			return ps;
		}

		public bool _ps_is_cur(IntPtr _ps)
		{
			Slot* ps = (Slot*)_ps;
			return ps != null && ps->gen >= gen;
		}
		public bool _ps_is_fwd(IntPtr _ps)
		{
			Slot* ps = (Slot*)_ps;
			return ps != null && ps->gen >= gen && ps->forward < 0;
		}

		/// <summary>
		/// unlike _ps_master, this returns null for the master itself. (only returns 'null' for old or null arg)
		/// </summary>
		public Slot* _ps_fwd(Slot* ps)
		{
			if (ps == null || ps->gen < this.gen)
				return null;
			int fwd;
			return (fwd = ps->forward) < 0 ? (Slot*)((long)ps_base - fwd) : null;
		}
		/// <summary>
		/// unlike _ps_master, this returns IntPtr.Zero for the master itself. (only returns 'null' for old or IntPtr.Zero arg)
		/// </summary>
		public IntPtr _ps_fwd(IntPtr ps)
		{
			if (ps == IntPtr.Zero || ((Slot*)ps)->gen < this.gen)
				return IntPtr.Zero;
			int fwd;
			return (fwd = ((Slot*)ps)->forward) < 0 ? (IntPtr)((long)ps_base - fwd) : IntPtr.Zero;
		}
		public int _total_forwarders(IntPtr target)
		{
			if (target == IntPtr.Zero || ((Slot*)target)->gen < this.gen)
				return 0;
			List<IntPtr> rgsd;
			if (!_reverse_forwarding_index.TryGetValue(target, out rgsd))
				return 0;
			return rgsd.Sum(x => _total_forwarders(x)) + rgsd.Count;
		}
		public IEnumerable<IntPtr> _all_forwarders(IntPtr target)
		{
			if (!_ps_is_cur(target))
				yield break;
			List<IntPtr> rgsd;
			if (_reverse_forwarding_index.TryGetValue(target, out rgsd))
			{
				foreach (IntPtr fs in rgsd)
				{
					foreach (IntPtr ffs in _all_forwarders(fs))
						yield return ffs;
					yield return fs;
				}
			}
		}

		public IEnumerable<IntPtr> _all_forwarders_and_self(IntPtr self)
		{
			if (_ps_is_cur(self))
			{
				List<IntPtr> rgsd;
				if (_reverse_forwarding_index.TryGetValue(self, out rgsd))
					foreach (IntPtr fs in rgsd)
						foreach (IntPtr ffs in _all_forwarders_and_self(fs))
							yield return ffs;
			}
			yield return self;
		}

		public int _immediate_forwarders(IntPtr target)
		{
			if (target == IntPtr.Zero || ((Slot*)target)->gen < this.gen)
				return 0;
			List<IntPtr> rgsd;
			return _reverse_forwarding_index.TryGetValue(target, out rgsd) ? rgsd.Count : 0;
		}
		public IReadOnlyList<IntPtr> _ps_fwd_sources(IntPtr target)
		{
			if (target == IntPtr.Zero || ((Slot*)target)->gen < this.gen)
				return Collection<IntPtr>.None;
			List<IntPtr> rgsd;
			if (_reverse_forwarding_index.TryGetValue(target, out rgsd))
				return rgsd;
			return Collection<IntPtr>.None;
		}
		public SlotPtr[] _sd_fwd_sources(IntPtr target)
		{
			if (target == IntPtr.Zero || ((Slot*)target)->gen < this.gen)
				return Collection<SlotPtr>.None;
			List<IntPtr> rgsd;
			return _reverse_forwarding_index.TryGetValue(target, out rgsd) ? ToSdArray(rgsd) : Collection<SlotPtr>.None;
		}

		public IEnumerable<ICollection<IntPtr>> fwd_chains(IntPtr ps_cur)
		{
			var rgip = _ps_fwd_sources(ps_cur);
			if (rgip.Count > 0)
				foreach (var ip in rgip)
					foreach (var ep in fwd_chains(ip))
						yield return ep.Append(ps_cur);
			else
				yield return new UnaryCollection<IntPtr>(ps_cur);
		}

		public String _format_forward_chain(IEnumerable<IntPtr> seq)
		{
			var e = seq.GetEnumerator();
			if (!e.MoveNext())
				return String.Empty;
			String s_feat = _ps_feat((Slot*)e.Current).ToUpperInvariant();
			String s = _format_ps((Slot*)e.Current, true);
			while (e.MoveNext())
			{
				s += "→" + _format_ps((Slot*)e.Current, true);
			}
			return s_feat.PadLeft(11) + "|" + s + "|";
		}


		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//static String[] rgsgen = { "   ", "nwf", "del", "ind", "pre", "fin", "g6", "g7" };
		//static String[] rgsgen = { "", "●ᐜ", "●?", "●✗", "●ᓑ", "●ᐦ", "g6", "g7" };
		//static String[] rgsgen = { "●", "●W", "●?", "●✗", "●U", "●\"", "g6", "g7" };
		static String[] rgsgen = { "", "ⴲ", "ⴱ", "ⵁ", "ⵝ", "□", "ⴷ", "ⵠ" };	//￭

		static String[] rgsogen = { "ⵔ", "●", "ⴲ", "ⴱ", "ⵁ", "ⵝ", "□", "ⴷ", "ⵠ" };

		//public String item_char(Scratch* ps)
		//{
		//    uint g = ps->gen;
		//    return g < gen ? "ⵝ" : g > gen + 5 ? "?" : g == gen + g_nwf ? "ⵔ" : "●";
		//}
		// "  202⊿→113∟→113∠→113∧→113∨→113∫→113∞→113∋→113∀→113∴→113∵→113∽→113□→113ⵝ  ",nq
		// "  113ⵉ→113ⵇ→113ⴽ→113ⴶ→113ⵕ→113ⵎ→113ⵏ→113ⵌ→113ⵍ→113ⵊ→113ⴰ→113ⵢ→113ⵔ→113ⵤ→113ⵗ→113ⵜ→113ⵑ→113ⵐ  ",nq

		public String _format_ps(IntPtr ps, bool f_show_num)
		{
			return _format_ps((Slot*)ps, f_show_num);
		}
		public String _format_ps(Slot* ps, bool f_show_num)
		{
			if (ps == null)
				return "(ps==null)";
			if (ps->uix == 0)
				return "(_thisix==0)";
			if (ps->forward > 0)
				return "(err: forward>0)";

			pinfo* pi = ps->gen < gen ? _find_pi_for_old(ps) : pbx + ps->tfsix;

			String s = alib.String._string_ext.SubscriptNum(pi->tfsix);

			if (ps->gen < gen)
				return s + "ⵔ";

			int m_src;
#if UNIF_V6
			if (ps->gen < 6)
				m_src = ps->m_src;
			else if (ps->uix == pi->uix0)
				m_src = pi->tfs._top_edge.Mark;
			else
				m_src = pi->entries[ps->uix - pi->uix0 - 1].e_Mark;
#else
			m_src = ps->m_src;
#endif
			if (m_src < 0 && ps == *(pi->coref_designations - m_src))
				s = '\u035F' + s;
			//s = "₍" + s + "₎"; // "￭"₊

			if (f_show_num)
				s += ps->uix.ToString();
			else if (ps->gen == gen)
				return s + "●";

			return s + rgsgen[(int)(ps->gen & (GEN_INCR - 1))];
		}

		public String _forward_chain_display(Slot* ps_start, bool f_first)
		{
			String s = _format_ps(ps_start, !f_first);
			Slot* psfwd = _ps_fwd(ps_start);
			return psfwd == null ? s : (s + "→" + _forward_chain_display(psfwd, false));
		}

		public String _fcd(Slot* ps, bool f_self)
		{
			String s = "";
			List<IntPtr> L;
			if (_reverse_forwarding_index.TryGetValue((IntPtr)ps, out L))
				s = "{" + L.PsSelect(x => _fcd(x, true)).StringJoin(" ") + "}";
			if (f_self)
				s += _format_ps(ps, true);
			return s;
		}

		public String _ps_feat(IntPtr ps)
		{
			return _ps_feat((Slot*)ps);
		}
		public String _ps_feat(Slot* ps)
		{
			pinfo* pi = _find_pi_for_old(ps);
			int ix = ps->uix - pi->uix0;
			if (ix < 0)
				throw new Exception();
			if (ix == 0)
				return String.Format("[#{0} {1}]", pi->tfsix, pi->tfs.Type.Name);
			var arr = pi->tfs.entries;
			if (--ix >= arr.Length)
				return "[error]";
			return ftm[arr[ix].i_feat].feature;
		}

#if REVERSE_INDEX
		public List<String> Paths(Slot* ps)
		{
			List<String> L = new List<string>();
			Slot*[] tps;
			String s_feat = _ps_feat(ps);
			if (s_feat == null || (tps = _tfs_parent_slots(ps)).Length == 0)
				L.Add(String.Format("(tfs #{0})", _find_pi_for_old(ps)->tfsix));
			else
			{
				foreach (Slot* q in tps)
					foreach (String sp in Paths(q))
						L.Add(sp + "." /*+ _format_ps(ps, true) + "/"*/ + s_feat);
			}
			return L;
		}

		public IEnumerable<ICollection<IntPtr>> _unifier_paths(IntPtr ps)
		{
			//if (_ps_is_fwd(ps))
			//    yield break;

			var tps = _all_forwarders_and_self(ps).SelectManyDistinct(af => _tfs_parent_master_slots(af));
			if (tps.Count == 0)
				yield return new UnaryCollection<IntPtr>(ps);
			else
				foreach (IntPtr q in tps)
					foreach (ICollection<IntPtr> up in _unifier_paths(q))
						yield return up.Append(ps);
		}

		public UnifierPath[] UnifierPaths(Slot* ps)
		{
			if (ps == null || ps->gen < gen)
				return Collection<UnifierPath>.None;

			var L = _unifier_paths((IntPtr)ps).ToList();

			UnifierPath[] arr = new UnifierPath[L.Count];
			for (int i = 0; i < arr.Length; i++)
				arr[i] = new UnifierPath(this, L[i]);

			Array.Sort(arr, UnifierPath.Comparer);
			return arr;
		}

		[DebuggerDisplay("{ToString(),nq}")]
		public struct UnifierPath
		{
			public UnifierPath(Unification u, ICollection<IntPtr> ic)
			{
				StringBuilder sb = new StringBuilder(80);
				this.path = new SlotPtr[ic.Count];
				int i = 0;
				foreach (IntPtr ps in ic)
				{
					Slot* x = (Slot*)ps;
					path[i++] = new SlotPtr(x);
					if (sb.Length > 0)
						sb.Append('.');
					sb.Append(u._ps_feat(x));
				}
				this.s = sb.ToString();
			}
			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			SlotPtr[] path;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			String s;

			public override string ToString() { return s; }

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public static readonly IComparer<UnifierPath> Comparer = new _cmp();

			class _cmp : IComparer<UnifierPath>
			{
				public int Compare(UnifierPath x, UnifierPath y)
				{
					if (x.s == y.s)
						return 0;
					if (x.s.StartsWith(y.s))
						return -1;
					if (y.s.StartsWith(x.s))
						return 1;
					return StringComparer.Ordinal.Compare(x.s, y.s);
				}
			};
		};
		public IntPtr[] _tfs_parent_master_slots(IntPtr _ps)
		{
			Slot* ps = (Slot*)_ps;
			pinfo* pi = _find_pi_for_old(ps);
			Tfs tfs;
			int ix = ps->uix - pi->uix0;
			if (ix <= 0 || (tfs = pi->tfs) == null || ix > tfs.c_act)
				return Collection<IntPtr>.None;

			int m = pi->entries[ix - 1].mark;
			int top_mark = tfs._top_edge.Mark;
			if (top_mark != 0 && m == top_mark)
			{
				Slot* x = ps_base + pi->uix0;
				if (x->gen < gen || x->forward == 0)
					return new IntPtr[] { (IntPtr)x };
				else
					return Collection<IntPtr>.None;
			}

			var rg = tfs.GetOutMarkSlots(m);
			if (rg.Length == 0)
				throw new Exception();

			if (rg.Length == 1)
			{
				Slot* x = ps_base + (pi->uix0 + rg[0]);
				if (x->gen < gen || x->forward == 0)
					return new IntPtr[] { (IntPtr)x };
				else
					return Collection<IntPtr>.None;
			}

			Slot** _qq = stackalloc Slot*[20];
			Slot** qq = _qq;
			for (int i = 0; i < rg.Length; i++)
			{
				Slot* x = ps_base + (pi->uix0 + rg[i]);
				if (x->gen < gen || x->forward == 0)
					*qq++ = x;
			}

			int c = (int)(qq - _qq);
			var arr = new IntPtr[c];
			while (c > 0)
				arr[--c] = (IntPtr)(*--qq);
			return arr;
		}

		public IntPtr[] _tfs_parent_slots(IntPtr _ps)
		{
			Slot* ps = (Slot*)_ps;
			pinfo* pi = _find_pi_for_old(ps);
			int ix = ps->uix - pi->uix0;
			if (ix <= 0)
				return Collection<IntPtr>.None;

			int m = pi->entries[ix - 1].mark;
			if (m == pi->tfs._top_edge.Mark)
				return new IntPtr[] { (IntPtr)(ps_base + pi->uix0) };

			var rg = pi->tfs.GetOutMarkSlots(m);
			if (rg.Length == 0)
				throw new Exception();

			if (rg.Length == 1)
				return new IntPtr[] { (IntPtr)(ps_base + (pi->uix0 + rg[0])) };

			Slot** _qq = stackalloc Slot*[20];
			Slot** qq = _qq;
			for (int i = 0; i < rg.Length; i++)
				*qq++ = ps_base + (pi->uix0 + rg[i]);

			int c = (int)(qq - _qq);
			var arr = new IntPtr[c];
			do
				arr[--c] = (IntPtr)(*--qq);
			while (c > 0);
			return arr;
		}

		public Slot*[] _tfs_parent_slots(Slot* ps)
		{
			pinfo* pi = _find_pi_for_old(ps);
			int ix = ps->uix - pi->uix0;
			if (ix <= 0)
				return rgps_none;

			int m = pi->entries[ix - 1].mark;
			if (m == pi->tfs._top_edge.Mark)
				return new Slot*[] { ps_base + pi->uix0 };

			var rg = pi->tfs.GetOutMarkSlots(m);
			if (rg.Length == 0)
				throw new Exception();

			if (m > 0)
				return new Slot*[] { ps_base + (pi->uix0 + rg[0]) };

			Slot** _qq = stackalloc Slot*[20];
			Slot** qq = _qq;
			for (int i = 0; i < rg.Length; i++)
				*qq++ = ps_base + (pi->uix0 + rg[i]);

			int c = (int)(qq - _qq);
			var arr = new Slot*[c];
			do
				arr[--c] = *--qq;
			while (c > 0);
			return arr;
		}

		public SlotPtr[] _tfs_parent_slots_sd(Slot* ps)
		{
			pinfo* pi = pbx + ps->tfsix;
			int ix = ps->uix - pi->uix0;
			if (ix <= 0)
				return Collection<SlotPtr>.None;

			int m = pi->entries[ix - 1].mark;
			if (m == pi->tfs._top_edge.Mark)
				return new SlotPtr[] { new SlotPtr(ps_base + pi->uix0) };

			var rg = pi->tfs.GetOutMarkSlots(m);
			if (rg.Length == 0)
				throw new Exception();

			if (m > 0)
				return new SlotPtr[] { new SlotPtr(ps_base + (pi->uix0 + rg[0])) };

			Slot** _qq = stackalloc Slot*[20];
			Slot** qq = _qq;
			for (int i = 0; i < rg.Length; i++)
				*qq++ = ps_base + (pi->uix0 + rg[i]);

			int c = (int)(qq - _qq);
			var arr = new SlotPtr[c];
			do
				arr[--c] = new SlotPtr(*--qq);
			while (c > 0);
			return arr;
		}
#endif

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}", Name = "{pi->tfsix.ToString().PadLeft(3),nq}{_exp,nq} {_range_display().PadLeft(15),nq} ({pi->SlotCount})")]
		public class u_pinfo
		{
			public u_pinfo(Unification u, pinfo* pi)
			{
				this.u = u;
				this.pi = pi;
			}
			public u_pinfo(pinfo pinf)
				: this(_inst, _inst.pbx + pinf.tfsix)
			{
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public pinfo* pi;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public Unification u;

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			Slot* ps_true
			{
				get
				{
					return u == null || pi == null ? null : u.ps_base + pi->uix0;
				}
			}

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			public SlotPtr[] _scr_debug_all
			{
				get
				{
					if (pi == null)
						return null;
					int c = pi->SlotCount;
					SlotPtr[] rgsd = new SlotPtr[c];
					Slot* ps = ps_true;
					for (int i = 0; i < c; i++, ps++)
						rgsd[i] = new SlotPtr(ps);
					return rgsd;
				}
			}

			[DebuggerDisplay("   {u._summary_counts(pi->tfsix,_sdf_old),nq}", Name = "old")]
			public SlotPtr[] zz1_debug_old
			{
				get
				{
					if (pi == null)
						return null;
					List<SlotPtr> lsd = new List<SlotPtr>();
					int c = pi->SlotCount;
					Slot* ps = ps_true;
					for (int i = 0; i < c; i++, ps++)
						if (ps->gen < u.gen)
							lsd.Add(new SlotPtr(ps));
					return lsd.ToArray();
				}
			}

			[DebuggerDisplay("   {u._summary_counts(pi->tfsix,_sdf_cur),nq}", Name = "normal")]
			public SlotPtr[] zz2_debug_cur_gen
			{
				get
				{
					if (pi == null)
						return null;
					List<SlotPtr> lsd = new List<SlotPtr>();
					int c = pi->SlotCount;
					Slot* ps = ps_true;
					for (int i = 0; i < c; i++, ps++)
						if (ps->gen >= u.gen)
							lsd.Add(new SlotPtr(ps));
					return lsd.ToArray();
				}
			}

			[DebuggerDisplay("   {u._summary_counts(pi->tfsix,_sdf_nwf),nq}", Name = "not well-formed")]
			public SlotPtr[] zz3_debug_nwf
			{
				get
				{
					if (pi == null)
						return null;
					List<SlotPtr> lsd = new List<SlotPtr>();
					int c = pi->SlotCount;
					Slot* ps = ps_true;
					for (int i = 0; i < c; i++, ps++)
						if (ps->Gen == 1)
							lsd.Add(new SlotPtr(ps));
					return lsd.ToArray();
				}
			}

			[DebuggerDisplay("   {u._summary_counts(pi->tfsix,_sdf_mst),nq}", Name = "master")]
			public SlotPtr[] zz4_debug_mst
			{
				get
				{
					if (pi == null)
						return null;
					List<SlotPtr> lsd = new List<SlotPtr>();
					int c = pi->SlotCount;
					Slot* ps = ps_true;
					for (int i = 0; i < c; i++, ps++)
						if (ps->gen >= u.gen && ps->forward == 0)
							lsd.Add(new SlotPtr(ps));
					return lsd.ToArray();
				}
			}

			[DebuggerDisplay("   {u._summary_counts(pi->tfsix,_sdf_fwd),nq}", Name = "forwarded")]
			public SlotPtr[] zz5_debug_fwd
			{
				get
				{
					if (pi == null)
						return null;
					List<SlotPtr> lsd = new List<SlotPtr>();
					int c = pi->SlotCount;
					Slot* ps = ps_true;
					for (int i = 0; i < c; i++, ps++)
						if (ps->gen >= u.gen && ps->forward < 0)
							lsd.Add(new SlotPtr(ps));
					return lsd.ToArray();
				}
			}

			[DebuggerDisplay("   {u._summary_counts(pi->tfsix,_sdf_nmf),nq}", Name = "non-master forward")]
			public SlotPtr[] zz6_debug_nmf
			{
				get
				{
					if (pi == null)
						return null;
					List<SlotPtr> lsd = new List<SlotPtr>();
					int c = pi->SlotCount;
					Slot* ps = ps_true;
					for (int i = 0; i < c; i++, ps++)
						if (ps->gen >= u.gen && ps->forward < 0 && ((Slot*)((long)u.ps_base - ps->forward))->forward < 0)
							lsd.Add(new SlotPtr(ps));
					return lsd.ToArray();
				}
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public String _exp
			{
				get
				{
					String s = "";
					if (pi != null)
					{
						if ((pi->tfs.flags & Tfs.Flags.Expanded) != 0)
							s += "E";
						else
							s += " ";
						if ((pi->tfs.flags & Tfs.Flags.Restrict) != 0)
							s += "R";
						else
							s += " ";
					}
					return s.PadRight(2);
				}
			}

			//[DebuggerDisplay("{(pi->gch_tfs.IsAllocated?pi->tfs.ToString():\"(not initialized)\"),nq}")]
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public Tfs tfs { get { return pi == null ? null : pi->tfs; } }

			public String _range_display()
			{
				if (pi == null)
					return "(not initialized)";
				int uix0 = pi->uix0;
				int uix2 = pi->uix0 + pi->SlotCount - 1;
				return String.Format("[{0}...{1}]", uix0, uix2);
			}

			public override String ToString()
			{
				try
				{
					Unification u = this.u;
					if (u == null)
						return "(u==null)";
					if (pi == null)
						return "(not initialized)";
					if (pi->tfsix <= 0)
						return "(tfsix <= 0)";

					String s = "";
					Slot* ps_topmst = u.ps_base + pi->uix0;
					Edge.Flag ef_cur = ps_topmst->f;
					//TypeMgr tm = ps_topmst->_tm;
					var fcm = ps_topmst->_ftm;

					s += String.Format("{0,40} {1}", u._summary_counts(pi->tfsix, null), Edge.TypeInfoFromFlag(fcm, ef_cur));

					Edge.Flag ef_tfs = pi->tfs._top_edge.FlagsId & ~Edge.Flag.Coreference;
					if (ef_tfs != ef_cur)
						s += String.Format(" (was: {0})", Edge.TypeInfoFromFlag(fcm, ef_tfs).Trim(alib.Character.Charset.outer_trim));
					return s;
				}
				catch (Exception ex)
				{
					return ex.ToString();
				}
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}")]
		[DebuggerTypeProxy(typeof(u_pinfo))]
		public partial struct pinfo
		{
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public int SlotCount
			{
				get
				{
					Tfs atfs;
					if (!gch_tfs.IsAllocated || (atfs = (Tfs)gch_tfs.Target) == null)
						return 0;
					return 1 + (int)tfs.SlotCount;
				}
			}

			public IEnumerable<IntPtr> Slots(Unification u)
			{
				int c = SlotCount;
				IntPtr ps = u._ps_base + (uix0 << SHL_PS);
				for (int i = 0; i < c; i++)
				{
					yield return ps;
					ps = ps + _sizeof_scratch;
				}
			}

			public void CorefCounts(Unification u, out int ctot, out int cnul, out int cmst, out int cfwd, out int cnmf, out int cind, out int ccnt)
			{
				cnul = 0;
				cmst = 0;
				cfwd = 0;
				cnmf = 0;
				cind = 0;
				ccnt = 0;
				ctot = tfs.c_corefs;
				if (ctot == 0)
					return;

				Slot** pps = coref_designations + 1;
				for (int j = 0; j < ctot; j++)
				{
					int fwd;
					Slot* ps = *pps;
					if (ps == null)
						cnul++;
					else
					{
						if ((fwd = ps->forward) == 0)
						{
#if P1_COUNT
							ccnt += ps->c_cnt;
#endif
							cmst++;
						}
						else
						{
							cfwd++;
							if (((Slot*)((long)u.ps_base - fwd))->forward < 0)
								cnmf++;
						}
					}
					pps++;
				}
			}

			public override String ToString()
			{
				fixed (pinfo* _this = &this)
					return new u_pinfo(_inst, _this).ToString();
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{_scr_debug.ToStringEx(true),nq}")]
		public partial struct Slot : IEquatable<Slot>
		{
			//public void get_source_coref_counts(out int c_pnd, out int c_loc)
			//{
			//    u.get_source_coref_counts(tfsix, e.Mark, out c_pnd, out c_loc);
			//}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public bool IsCurrentGen { get { return gen >= _u.gen; } }

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public int Gen { get { return gen < _u.gen ? -1 : (int)(gen & (GEN_INCR - 1)); } }

			/// <summary>
			/// The generated IL for this is not as bad as it would seem, but it is still preferable
			/// to provide the correct unifier and compute 'ps_base + ps->_thisix'
			/// </summary>
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			Slot* _this { get { fixed (Slot* ps = &this) return ps; } }

			public override int GetHashCode() { return (int)_this; }

			public bool Equals(Slot other) { fixed (Slot* ps = &this) return ps == other._this; }

			public override bool Equals(object obj) { return obj is Slot && Equals((Slot)obj); }

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			public SlotPtr _scr_debug { get { fixed (Slot* ps = &this) return new SlotPtr(ps); } }

			public override String ToString()
			{
				String s;
				fixed (Slot* ps = &this)
					s = new SlotPtr(ps).ToString();
				return s;
			}

			public int _dbg_tfs_find_mark(Unification u)
			{
				pinfo* pi = u.pbx + tfsix;
				int ix1 = uix - pi->uix0;
				if (ix1 < 0)
					throw new Exception();
				if (ix1 == 0)
					return pi->tfs._top_edge.Mark;
				return pi->entries[ix1 - 1].mark;
			}

			public bool _dbg_is_topmost(Unification u)
			{
				return uix == (u.pbx + tfsix)->uix0;
			}

			public Slot* _dbg_tfs_parent_slot(Unification u)
			{
				int m = _dbg_tfs_find_mark(u);
				if (m == 0)
					throw new Exception();

				pinfo* pi = u.pbx + tfsix;

				Slot* ps = u.ps_base + pi->uix0;
				if (ps->gen >= u.gen && ps->m_src == m)
					return ps;
				ps++;

				arr_tfs_entry* pate = pi->entries;
				int c = pi->tfs.entries.Length;
				int i = 0;
				while (i < c)
				{
					if (pate->e_Mark == m && ps->gen >= u.gen)
						return ps;
					pate++;
					ps++;
					i++;
				}
				return null;
			}

		};
	};
#else
	public unsafe sealed partial class Unification
	{
		[Conditional("_never_")]
		void _debug_new() { }
		[Conditional("_never_")]
		void _debug_init() { }
		[Conditional("_never_")]
		void _debug_dispose() { }
		[Conditional("_never_")]
		void _debug_tfs_init(pinfo* pi) { }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Slot* ps_last { get { return ps_base + (pbx + c_participants + 1)->uix0; } }
	};
#endif

	public unsafe sealed partial class Unification
	{
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int ix_last { get { return (pbx + c_participants + 1)->uix0; } }

#if false
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		bool unify_no_coref(Scratch* ps, Tfs tfs, int mark, out bool f_ok)
		{
			Nop.Untested();
			Debug.Assert(ps->m_src != 0 && ps->forward == 0 && (ps->f & Edge.Flag.EtmNonBareType) != 0);
			f_ok = true;

			Scratch* nps;
			Scratch* nxt = ps_last;
			ushort* pfix;
			int i_feat = *(pfix = *(ushort**)((long)rgpfix + ((int)ps->f << 3)));
			do
			{
				int nm;
				Edge.Flag nf = tfs.TryGetFlagsMark(i_feat, mark, out nm);
				if (nf < 0 || nm < 0)
					throw new Exception();
				if (nf == 0)
					continue;

				if ((nps = _source_fetch(ps, pbx + ps->tfsix, i_feat)) == null)
				{
					nps = nxt++;
					return true;
				}
				else
				{
					Edge.Flag f1, f2;
					if ((f2 = nps->f) != nf && f2 != 0)
					{
						if ((nf = tm.UnifyTypes(f2, f1 = nf)) < 0)
							return false;
						if (nf != f1 && nf != f2)
						{
							f_ok = false;
							Console.Write("b");
							return true;
						}
					}
				}
				nps->f = nf;

				if (nm != 0)
				{
					if (nps->m_src == 0)
					{
						f_ok = false;
						Console.Write("c");
						return true;
					}
					if (!unify_no_coref(nps, tfs, nm, out f_ok))
						return false;
				}
				if (!f_ok)
					return true;
			}
			while ((i_feat = *++pfix) != 0xFFFF);

			return true;
		}
#endif
	};
}
